x-kom hosting

[C++] Niespodziewany wynik (przeliczanie systemów liczbowych)

Przejdź do rekomendowanej odpowiedzi Autor: rafalluz ,
diego411
utworzono
utworzono (edytowane)

Witam. Mam problem z programem. Otóż napisałem taki aby przeliczał dowolny system (2-36) na dowolny inny (2-36).

Problem niestety występuje z wynikiem.

Screen z działania programu: http://www.iv.pl/images/05429481119188939834.png

Jak widać na screenie wynik to 193 a powinien być 194. Wielkość błędu jest wprost proporcjonalna do wielkości liczby, czyli jak dam większą to będzie większa rozbieżność między moim wynikiem a tym prawidłowym.

Ostatnie działanie wykonywane w programie to 69+125 więc jak nic musi wyjść 194..

Kod w którym występuje błąd:

        string OliczbaS=""; //na poczatku musimy odwrocic podana liczbe
        for(int i=0;i<liczbaS.size();i++) // petla odwracajaca
            OliczbaS+=liczbaS[liczbaS.size()-i-1];
        int j; int wyn=0;
        for(int i=0;i<OliczbaS.size();i++) // petla robi dopoki nie skoncza sie znaki w liczbie
        {
            j=0;
            while(OliczbaS[i]!=znaki[j]) j++; // petla szuka pozycji znaku w znakach systemow
            //cout << "wyn: " << wyn << "  potega: " << pow(sys,i) << "   i: " << i << "   j: " << j << endl;
            wyn+=j*pow(sys,i); // do wyniku dodajemy wartosc kolejnego znaku z liczby, pow - funkcja potegujaca
            //cout << "///wyn: " << wyn << "  potega: " << pow(sys,i) << "   i: " << i << "   j: " << j << endl;
        }

gdzie liczbaS=="1234" 

znaki="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"

sys==5 (system piątkowy) 

 

Problem występuję tylko w przeliczaniu z systemu 5 (piątkowego).

Proszę o pomoc.

rafalluz
komentarz
komentarz (edytowane)

U mnie pod VS2010 działa poprawnie, zmieniłem:

wyn+=j*pow(sys,i);

na:

wyn+=j*pow((double)sys,i);

I działa jak należy - VS nie pozwala na składnię nr #1, wyrzuca błąd kompilatora z uwagi na niejednoznaczne odwołanie.

 

Swoją drogą to na razie przelicza tylko z dowolnego na 10tkowy jak rozumiem?

Garrappachc
komentarz
komentarz

Odwracanie stringa można zrobić ładniej ;)

string OliczbaS(liczbaS);
std::reverse(OliczbaS.begin(), OliczbaS.end());

std::reverse

 

Zmienna sys jest intem czy doublem?

rafalluz
komentarz
komentarz

A można go w ogóle nie robić, tylko zmienić warunki w forze ;)

 

To jedna optymalizacja.

 

Druga, to przyspieszenie znajdowania j, można to zrobić bez przeszukiwania stringa znaki.

diego411
komentarz
komentarz (edytowane)

rafalluz - sprawdziłem Twoją składnie lecz również daje zły wynik. Przeliczanie z dowolnego systemu na 10 odbywa się tylko tutaj gdyż przed owym blokiem jest warunek if(sys2==10), a zaraz po wypisanie wyniku, nie ma niczego co mogło by zmienić wartość. 

Drugi blok którego nie używa program w przypadku przeliczania z dowolnego na 10 jest niżej ze względu na konstrukcje, gdyż gdybym chciał przeliczyć z dowolnego na dowolny to najpierw zamieniam na 10 a później na ten docelowy. 

Wiem też że mogę użyć metody find ze stringa, powód dlaczego tego nie zrobiłem linijka niżej.

Garrappachc - Program jest celowo zrobiony tak a nie inaczej gdyż mam go pokazać kilku osobom które nie zapoznały się jeszcze z funkcjami i wieloma innymi rzeczami. I dlatego również nie jest pisany w funkcji oddzielnej tylko w głównej main. 

 

// w zasadzie po chwili namysłu zoptymalizuje go trochę, przynajmniej nauczą się nowych rzeczy.

Później podam nowe przykłady działania programu, gdyż za cholerę nie mogę sam znaleźć błędu.

  • Rekomendowana odpowiedź
rafalluz
komentarz
komentarz (edytowane)

Nie find(), ona nadal ma czas liniowy działania, można to zrobić w czasie stałym.

int find_cyfra(char c)
{
    if(c>='0' && c<='9')
        return c - '0';//'0' == 48
    else if(c>='A' && c<='Z')
        return c - 'A' + 10; //'A' == 65
    else
        return -1;
}

int _tmain(int argc, _TCHAR* argv[])
{
    string liczbaS = "1234";
    int sys = 5;
    string znaki="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    int j; int wyn=0;
    for(int i=liczbaS.size()-1; i>=0;i--) // petla robi dopoki nie skoncza sie znaki w liczbie
    {
    int j=find_cyfra(liczbaS[i]);
    wyn+=j*pow((double)sys,(int)(liczbaS.size() - 1 - i)); // do wyniku dodajemy wartosc kolejnego znaku z liczby, pow - funkcja potegujaca
    }
    cout << wyn << endl;
    system("pause");
    return 0;
}

Musisz nieco zmienić, by się skompilował - na pewno deklarację main().

 

U mnie zwraca poprawnie 194.

 

Jeśli nadal masz błąd, porzuć funkcję pow i zamiast tego zastosuj schemat Hornera - jest to też szybsza metoda.

  • Dobra wypowiedź 1
diego411
komentarz
komentarz (edytowane)

Fajny sposób.

        int wyn=0,j;
        for(int i=liczbaS.size()-1;i>=0;i--) // petla robi dopoki nie skoncza sie znaki w liczbie
        {
            if(liczbaS[i]>='0' && liczbaS[i]<='9')
                j=liczbaS[i] - '0';//'0' == 48
            else if(liczbaS[i]>='A' && liczbaS[i]<='Z')
                j=liczbaS[i] - 'A' + 10; //'A' == 65
            wyn+=j*pow(sys,(liczbaS.size()-1-i));//wyn+=j*pow(sys,i); // do wyniku dodajemy wartosc kolejnego znaku z liczby, pow - funkcja potegujaca
        }

taki zapis działa doskonale.

I racja, te pętle odwracające były trochę niepotrzebne bo równie dobrze mogę użyć zapisu: tekst=znak+tekst; i będzie na początku dodawany znak. A wcale nie jest trudniej.

 

Dzięki za rozwiązanie problemu i pomoc w optymalizacji. Pozdrawiam.

Wciąż szukasz rozwiązania problemu? Napisz teraz na forum!

Możesz zadać pytanie bez konieczności rejestracji - wystarczy, że wypełnisz formularz.

×
×
  • Dodaj nową pozycję...

Powiadomienie o plikach cookie

Strona wykorzystuje pliki cookies w celu prawidłowego świadczenia usług i wygody użytkowników. Warunki przechowywania i dostępu do plików cookies możesz zmienić w ustawieniach przeglądarki.