Problem z wyciągnięciem pierwszej liczby po przecinku
Ostatnio zmodyfikowano 2013-11-01 15:56
maly |
» 2013-10-31 08:53:51 Sprawdziłeś czy tylko tak myślisz? |
|
Nekronomik Temat założony przez niniejszego użytkownika |
» 2013-10-31 09:04:59 Sprawdziłem. |
|
maly |
» 2013-10-31 09:08:23 To dziwne bo ja sprawdziłem na gcc 4.8.1 i C++ Builder 6 i działa. Jaki masz kompilator? |
|
Nekronomik Temat założony przez niniejszego użytkownika |
» 2013-10-31 09:18:34 Dev-C++ 4.9.9.2 gcc 3.4.2 |
|
maly |
» 2013-10-31 09:29:15 Trochę stary ten kompilator. Przykład na kompilatorze online http://ideone.com/sivaeB//EDIT Sprawdziłem jeszcze na gcc-3.4.5 i jest OK, więc niewiem co jest nie tak. |
|
Nekronomik Temat założony przez niniejszego użytkownika |
» 2013-10-31 10:57:12 z gcc 4.7.2 jest to samo |
|
Nekronomik Temat założony przez niniejszego użytkownika |
» 2013-11-01 11:26:22 Żeby mi to działało to musiałem dodać liczbę 0.01 np: int(a+0.01*10.0)%10 albo double fraction = modf( number+0.01, & integer ); Jestem tylko ciekawy dlaczego mi to bez dodania liczby 0.01 nie działa. |
|
den93 |
» 2013-11-01 15:56:44 Rzecz w tym, że liczby zmiennoprzecinkowe są zapisywane w pamięci w postaci wykładniczej o podstawie systemu liczbowego równego 2. O co chodzi? Np.: 0.5 = 1 * 2^-1 0.25 = 1* 2^-2 0.75 = 1.5 * 2^-1 3.125 = 1.5625 * 2^1 itp. Czyli: <1; 2) * 2 ^ wykładnik
Idźmy dalej. Zajmijmy się mantysą. Mantysa tzn. to <1; 2) jest zapisana w pamięci na ograniczonej liczbie bitów w postaci dwójkowej. Nie każda część ułamkowa zapisana precyzyjnie w systemie (10) może być równie precyzyjnie zapisana w systemie (2) na iluś tam bitach (i stąd te problemy). Może przykłady: 1.5 (10) = 1.1 (2) // ok 1.25 (10) = 1.01 (2) // ok 1.3125 (10) = 1.0101 (2) // ok ale: 1.1 (10) = 1.0(0011) (2) // !!! ułamek dwójkowy okresowy nasz przypadek: 1.4 (10) = 1.(0110) (2) // !!! Ad hoc weźmy sobie 16 bitów (2 bajty) i spróbujmy to tam zapisać: 1.0110011001100110(0110) 1.0110011001100110 // !!! obcięto 0.0000000000000000(0110) szesnastkowo: 1.6666 (16) // 0.0000(6) dziesiętne: 1.399993896484375 // 0.000006103515625 błąd: ~0.000436%
dalej: int(x * 10.0) % 10 10 = 1.25 * 2^3 // 1.25 jest precyzyjne, patrz wyżej, można spokojnie mnożyć 1.399993896484375 * 10.0 = 13.99993896484375 int(13.99993896484375) = 13 // obcinanie ułamka dziesiętnego 13 % 10 = 3
ale (1.399993896484375+0.01) * 10.0 = ~1.409993896484375 * 10.0 = ~14.09993896484375 int(14.09993896484375) = 14 14 % 10 = 4
Twój sposób jest na krótką metę dobry, wystarczający ale nie idealny, powoduje utratę precyzji. Polecam zmienić kompilator na jakiś nowszy, które przy zamianie zmiennoprzecinkowej na integera nie obcinają tak restrykcyjnie części ułamkowej a raczej odpowiednio zaokrąglają liczbę zgodnie z oczekiwaniami. |
|
1 « 2 » |