php programmer
8.08.2007, 07:35:09
Oto kod
<?php
?>
Który wyświetla mi
50
49
Jakoby zaokrągleniem w dół liczby 50 było 49!
Czy ktoś wie dlaczego mi tak robi i jak to ominąć.
cicik
8.08.2007, 07:49:01
W sumie dziwne bo jak za $liczba podstawi się 50 to jest OK.
Podejrzewam, że na naszych niedoskonałych procesorach 7/0.14 = 49.999999999999999999 (to tylko przykład). Zwykłe wyświetlanie wyniku pewnie zaokrągla na którymś miejscu po przecinku i wychodzi 50. Natomiast floor pewnie bierze całą liczbę i zaokrągla w dół. Aczkolwiek sprawa ciekawa. W wolnej chwili zobaczę jak to wygląda w innych językach i kompilatorach.
grzemach
8.08.2007, 07:57:13
a musisz koniecznie wykorzystywać floor? nie mozesz np spróbować round()?
php programmer
8.08.2007, 07:58:48
round to nie floor,
ale chyba potraktuje to strpos i substr
cicik
8.08.2007, 08:15:43
Kod C#, kompilator VS .Net 2005, procesor Intel Centrino, system Windows XP Professional
<?php
double liczba = 7.0 / 0.14;
Console.WriteLine(liczba);
Console
.WriteLine
(Math
.Floor(liczba
));?>
Wynik:
<?php
50
49
?>
Kod C++, kompilator VS .Net 2005, procesor Intel Centrino, system Windows XP Professional
<?php
double liczba;
liczba = 7.0 / 0.14;
cout << liczba << endl;
cout
<< floor(liczba
) << endl
;?>
Wynik:
<?php
50
49
?>
Pod Demianem pracującym na AMD Athlonie XP 2500+ kod w C++ daje taki sam zły wynik.
Grzyw
8.08.2007, 08:47:17
Analogie to powyższego przykładu spotkałem w literaturze swego czasu. Błąd faktycznie bierze się z niedoskonałości liczenia procesorów, jest nie do wyeliminowania drogą bezpośrednią, wynik zawsze będzie błędny.
cicik
8.08.2007, 09:13:38
Pewnie kluczem do rozwiązania zagadki jest to, że liczba 0.1 jest liczbą niewymierną w systemie dwójkowym, a 0.14 = 0.1 + 0.04.
Procesory stosują różne triki, żeby tę cechę wyeliminować ale jak widać nie zawsze działa.
Aczkolwiek kiedyś miałem taki problem, że pisałem program do obliczania jakimi monetami wydać resztę w sklepie (na jakiś konkurs to było). Chodziło to aby badać reszty z dzielenia. No i generalnie na Intelach wyniki dzielenia (albo zaokrąglania - to dawno było) były inne od tych uzyskanych na AMD - tym samym kodem źródłowym!!! To mnie wtedy dość mocno zaskoczyło bo procesory przechodzą bardzo ostre testy na poprawność działania jednostki arytmetycznej, zwłaszcza tej zmiennoprzecinkowej. Historia o tym jak kiedyś wybuchła jakaś rakieta kosmiczna bo któryś Pentium źle liczył jest dość znana.
likemandrake
8.08.2007, 09:29:59
Problem polega wlasnie na tym co mowil moj poprzednik, aby ten temat sobie blizej przyblizyc, nalezy poczytac o tym, jak binarnie sa kodowane liczby po przecinku i mowa tu o liczbach zmiennoprzecinkowych. Cala sprawa kreci sie wtedy wokol kodowania FP2.
Na szybko mowiac, dla przykladu mamy taki ciag binarny (podzielony na grupy):
1|101|100101
liczba w pierwszej grupie jest to znak (+/-)
liczby w drugiej jest to cecha, inaczej zakres liczby
liczby w trzeciej grupie to mantysa, jest to tak naprawde nasza liczba, tyle ze zamieniona tak, zeby byla po przecinku
Jest wzór, wg którego obliczamy (odkodowujemy) liczbę zawartą w tym kodzie, ale ze względu na użyte potęgi, nie podałem go tu, a więc zainteresowanych odsyłam do google.pl
Chodzi o to, ze im mamy część całkowitą dalszą od zera, tym jej wartość po przecinku staje sie mniej dokladna i coraz bardziej zaokraglana wraz ze zwiększaniem tej odległości.
Co do problemu postawionego w tym poście, mam rozumieć, że w obu przypadkach chcemy uzyskać liczbę 50?
Kosmi
8.08.2007, 09:49:35
Cytat(php programmer @ 8.08.2007, 08:35:09 )

Oto kod
<?php
?>
Który wyświetla mi
50
49
Jakoby zaokrągleniem w dół liczby 50 było 49!
Czy ktoś wie dlaczego mi tak robi i jak to ominąć.
Na szybko może tak:
<?php
?>
Wynik:
50
50
Musiałbyś jedynie dobrze dobrać dokładność zaokrąglenia.
Ludvik
8.08.2007, 10:24:02
To nie ma sensu. Liczba 50.6 zostanie zaokrąglona do 51, a nie o to chodzi.
php programmer: Próbowałeś rzutowania na integer? Rzuć okiem, ja w tej chwili nie mam jak tego sprawdzić...
Kosmi
8.08.2007, 10:38:18
Cytat(Ludvik @ 8.08.2007, 11:24:02 )

To nie ma sensu. Liczba 50.6 zostanie zaokrąglona do 51, a nie o to chodzi.
php programmer: Próbowałeś rzutowania na integer? Rzuć okiem, ja w tej chwili nie mam jak tego sprawdzić...
<?php
?>
Wynik:
50.6
50
Przez to pisałem o dokładności zaokrąglenia.
Pozdrawiam
Kosmi
akubiczek
8.08.2007, 10:42:23
Cytat(Ludvik @ 8.08.2007, 11:24:02 )

To nie ma sensu. Liczba 50.6 zostanie zaokrąglona do 51, a nie o to chodzi.
Jakie 50.6? Tam jest zaokrąglanie z dokładnością do 6 miejsc po przecinku. I wydaje się to być dobrym pomysłem.
Poza tym dodam jeszcze od siebie - zamienić dzielenie na mnożenie:
<?php
echo $liczba = 7
*(1
/0
.14
); ?>
50
50
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę
kliknij tutaj.