Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Problem z wyciągnięciem pierwszej liczby po przecinku

Ostatnio zmodyfikowano 2013-11-01 15:56
Autor Wiadomość
maly
» 2013-10-31 08:53:51
Sprawdziłeś czy tylko tak myślisz?
P-94917
Nekronomik
Temat założony przez niniejszego użytkownika
» 2013-10-31 09:04:59
Sprawdziłem.
P-94918
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?
P-94919
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
P-94921
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.
P-94922
Nekronomik
Temat założony przez niniejszego użytkownika
» 2013-10-31 10:57:12
z gcc 4.7.2 jest to samo
P-94928
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.
P-95013
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.
P-95022
1 « 2 »
Poprzednia strona Strona 2 z 2