double on the floor
Krótko ilustrowana opowieść o tym, jak skomplikowana bywa praca programisty:
Prosta(?) operacja na typie double w eMbedded Visual C++ 4.0
Wyjaśnienie dodatkowe: zmienne n
i x
są typu double
, fact
to int
.
Wyjaśnienie dodatkowe dla mało widzących: wg kompilatora Microsoft eMbedded Visual C++ 4.0 zmienna typu double
o wartości 538,06 (i nie tylko, wczoraj w jednej chwili poznałem 16 wartości o takiej właściwości) pomnożona przez 10000 i obcięta w dół do liczby całkowitej daje w wyniku liczbę 5380599,0.
PS: Niestety przypadek ten wyśledziłem w autentycznym, działającym systemie. Na szczęście nie jest to system naprowadzania rakiet. Na obrazku powyżej nazwa projektu została wykreślona w celu ochrony niewinnych...
2005.04.15 | 6 komentarzy |
tagi » sztuka programowania
Komentarze
#1 | 2005.04.15 09:00 | Łukasz Grabuń
Na rysunku widać w jaki sposób wyświetlana jest wartość zmiennej n (na boczku: co to za zwyczaj używania litery N do oznaczenia nie liczby naturalnej, a quasi-rzeczywistej :-). Próbowałeś wypisać na wyjściu wartość tej zmiennej? Być może w istocie wartość wynosi 538.0599000?
Jeśli jednak to błąd kompilatora... Uch, potworny babol. Przypomina mi moją zabawę z fakturą.
#2 | 2005.04.15 09:48 | MiMaS
Hmmm, dobrze kombinujesz, ale niestety nie masz racji... Obie zmienne n
i x
są wyświetlanie przez debugger zgodnie z faktycznymi wartościami. Na pewno.
Może jeszcze słowo na temat otoczenia: rzecz odbywa się na PDA (PocketPC 2003) i dotyczy zapisu do bazy danej pobranej z serwera. Zapis odbywa się za pośrednictwem biblioteki napisanej w eMbedded C++ z powodów ... powiedzmy wydajnościowych. Na serwerze jest na pewno wartość 538,0600 i taka też jest wartość zmiennej n
. W bazie SQLCE na PDA jest zapisywane 538,0599 — wynik wartości pośredniej zmiennej x
. Sprawdzone na 100%.
#3 | 2005.04.20 13:10 | gshegosh
Nie chciałbym się specjalnie wymądrzać, ale reprezentacja liczb w systemie dwójkowym potrafi sprawiać takie niespodzianki - dla przykładu dziesiętnie mamy 0,1 ale gdy próbujemy tę liczbę przedstawić dwójkowo - okaże się, że rozwinięcie jest nieskończone (podobnie jak w systemie dziesiętnym nieskończone jest rozwinięcie 1/3). A przecież double jest trzymany w skończonej liczbie bitów... I problem z zaokrągleniami gotowy.
Na zaokrąglenia jest nawet standard IEEE (http://www.math.byu.edu/~schow/work/IEEEFloatingPoint.htm).
Rozwiązaniem jest stosowanie intów (real programmers use integers ;) lub też klas typu BigDecimal w Javie...
#4 | 2005.04.20 14:10 | MiMaS
przecież double jest trzymany w skończonej liczbie bitów... I problem z zaokrągleniami gotowy.
Bingo :-)
Jednak nie zmienia to faktu, że praca programisty bywa bardziej skomplikowana niż się wielu wydaje. Co więcej, z obserwacji rzeczywistości wnioskuję, że mało kogo obchodzą takie pierdoły jak precyzja/reprezentacja liczby... Efekt — wspomiane 16 przypadków na raz. Tylko, że tym razem to już się nie nazywało „niespodzianki” tylko „źle zapisane pozycje faktur”...
Rozwiązaniem jest stosowanie intów
A jak zamienisz na int skoro pomnożenie przez inta (fact
w przykładzie) już powoduje błąd..? ;-)
lub też klas typu BigDecimal w Javie...
Fajnie. Tylko niestety to jest eMVC++ a nie Java...
#6 | 2005.06.23 05:19 | sprae
W gcc natomiast wychodzi wartosc "poprawna" - 5380600.00
Uwaga: Ze względu na bardzo intensywną działalność spambotów komentowanie zostało wyłączone po 60 dniach od opublikowania wpisu. Jeżeli faktycznie chcesz jeszcze skomentować skorzystaj ze strony kontaktowej.