Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> Poważny błąd obliczeń w PHP 5.x, PHP nie umie dodawać licz ujemnych w pętli
icemanwlkp
post 18.12.2010, 12:27:49
Post #1





Grupa: Zarejestrowani
Postów: 50
Pomógł: 1
Dołączył: 29.09.2010

Ostrzeżenie: (0%)
-----


  1. $historia = Array('1195.61','-400.00','-200.00','-200.00','-395.61');
  2. $brutto = 0;
  3. foreach($historia as $poz)
  4. {
  5. echo $brutto.' + '.$poz.' = ';
  6. $brutto = $brutto + $poz;
  7. echo $brutto.'<BR>';
  8. }


Wynik :

0 + 1195.61 = 1195.61
1195.61 + -400.00 = 795.61
795.61 + -200.00 = 595.61
595.61 + -200.00 = 395.61
395.61 + -395.61 = -1.13686837722E-13 - co to za brednie ?
Go to the top of the page
+Quote Post
kalmaceta
post 18.12.2010, 12:42:02
Post #2





Grupa: Zarejestrowani
Postów: 183
Pomógł: 24
Dołączył: 4.12.2010

Ostrzeżenie: (0%)
-----


http://php.net/manual/en/language.types.float.php
http://pl.wikipedia.org/wiki/Liczba_zmiennoprzecinkowa

Ten post edytował kalmaceta 18.12.2010, 12:43:10


--------------------
kAlmAcetA
Go to the top of the page
+Quote Post
icemanwlkp
post 18.12.2010, 12:50:53
Post #3





Grupa: Zarejestrowani
Postów: 50
Pomógł: 1
Dołączył: 29.09.2010

Ostrzeżenie: (0%)
-----


Wiem co to jest liczba zmiennoprzecinkowa i wiem jak rozwiązać ten problem , żeby wynik wyszedł zero , pytam się tylko dlaczego w ostatnim wierszu wynik nie wynosi zero !

Błąd powstaje w tej lini :
  1. $brutto = $brutto + $poz;


nie działa również jeśli zrobimy tak:
  1. $brutto = (float)$brutto + (float)$poz;


nie działa również jeśli zrobimy tak:
  1. $brutto = floatvar($brutto) + floatvar($poz);


nie działa również jeśli zrobimy tak:
  1. $brutto = $brutto + round($poz,2);


rozwiązanie :
  1. $brutto = round($brutto,2) + $poz;


DLACZEGO TAK questionmark.gifquestionmark.gifquestionmark.gif MUSI BYĆ !

Ten post edytował icemanwlkp 18.12.2010, 13:00:04
Go to the top of the page
+Quote Post
Mephistofeles
post 18.12.2010, 13:06:36
Post #4





Grupa: Zarejestrowani
Postów: 1 182
Pomógł: 115
Dołączył: 4.03.2009
Skąd: Myszków

Ostrzeżenie: (0%)
-----


Skoro wiesz co to float, to powineneś także wiedzieć, że zapisywanie jej przez komputer nie jest dokładne. Do precyzyjnych obliczeń stosuje się typy stałoprzecinkowe, a w PHP http://pl2.php.net/bcmath,
Go to the top of the page
+Quote Post
kalmaceta
post 18.12.2010, 13:18:45
Post #5





Grupa: Zarejestrowani
Postów: 183
Pomógł: 24
Dołączył: 4.12.2010

Ostrzeżenie: (0%)
-----


Za wikipedią
Cytat
Arytmetyka zmiennoprzecinkowa nie jest łączna. To znaczy, że dla x, y i z mogą zachodzić różności:


--------------------
kAlmAcetA
Go to the top of the page
+Quote Post
Zyx
post 18.12.2010, 13:25:53
Post #6





Grupa: Zarejestrowani
Postów: 952
Pomógł: 154
Dołączył: 20.01.2007
Skąd: /dev/oracle

Ostrzeżenie: (0%)
-----


Jakbyś wiedział, co to jest liczba zmiennoprzecinkowa, a zwłaszcza - jak ona działa, to byś wiedział też, dlaczego tak musi być.

Podpowiedź: wartość 1195.61 nie może być reprezentowana dokładnie w binarnym zapisie, a 395.61 ma dokładną reprezentację. Aby było śmieszniej, już przy pierwszym dodawaniu procesor matematyczny (tak, procesor matematyczny, a nie żadne PHP) musi trochę sobie pomanipulować mantysami i w efekcie wykonuje operację, której skutkiem ubocznym jest dalsza utrata precyzji:

Kod
1.1956099999999999e+3 -4.0000000000000000e+2 = 7.9560999999999990e+2


--------------------
Specjalista ds. głupich i beznadziejnych, Zyx
Nowości wydawnicze: Open Power Collector 3.0.1.0 | Open Power Autoloader 3.0.3.0
Go to the top of the page
+Quote Post
flashdev
post 18.12.2010, 13:34:21
Post #7





Grupa: Zarejestrowani
Postów: 812
Pomógł: 117
Dołączył: 2.12.2008

Ostrzeżenie: (10%)
X----


Cytat(icemanwlkp @ 18.12.2010, 12:27:49 ) *
  1. $historia = Array('1195.61','-400.00','-200.00','-200.00','-395.61');
  2. $brutto = 0;
  3. foreach($historia as $poz)
  4. {
  5. echo $brutto.' + '.$poz.' = ';
  6. $brutto = $brutto + $poz;
  7. echo $brutto.'<BR>';
  8. }


Wynik :

0 + 1195.61 = 1195.61
1195.61 + -400.00 = 795.61
795.61 + -200.00 = 595.61
595.61 + -200.00 = 395.61
395.61 + -395.61 = -1.13686837722E-13 - co to za brednie ?


Jak to? Przecież liczy bardzo dobrze smile.gif
Przy takich obliczeniach jakie tu wykonujesz to przecież już **e-3 można uznać za zero, a gdzie tam jeszcze do -13 smile.gif
Przecież i tak przed wyświetleniem wartości wypada ją zaokrąglić do całych gorszy, nieprawdaż?

  1. $historia = Array('1195.61','-400.00','-200.00','-200.00','-395.61');
  2. $brutto = 0;
  3. foreach($historia as $poz)
  4. {
  5. echo $brutto.' + '.$poz.' = ';
  6. $brutto = $brutto + $poz;
  7. echo round($brutto, 2)."\n"; // tutaj poprawilem
  8. }


Edit:
Inne wersje PHP i wszystkie koprocesory też mają taki "błąd", więc naywając tak ten temat wprowadzasz czytelników w błąd winksmiley.jpg

Ten post edytował flashdev 18.12.2010, 13:37:06


--------------------
Go to the top of the page
+Quote Post
kiler129
post 18.12.2010, 22:43:36
Post #8





Grupa: Zarejestrowani
Postów: 566
Pomógł: 35
Dołączył: 21.06.2006

Ostrzeżenie: (0%)
-----


W niektórych wypadkach nawet taki kod:
  1. $x = 3.14;
  2. echo ($x*2)/(2*$x)+$x-1-$x;


nie wypluje zera smile.gif
To całkiem normalne zachowanie i też się na tym przejechałem ;]

Ten post edytował kiler129 18.12.2010, 22:44:04


--------------------
flexiCMS v2 [|||||||+--] 75% done
Go to the top of the page
+Quote Post
erix
post 18.12.2010, 23:06:29
Post #9





Grupa: Moderatorzy
Postów: 15 467
Pomógł: 1451
Dołączył: 25.04.2005
Skąd: Szczebrzeszyn/Rzeszów




Niby porównywanie floata przez ==. [;


--------------------

ZCE :: Pisząc PW załączaj LINK DO TEMATU i TYLKO w sprawach moderacji :: jakiś błąd - a TREŚĆ BŁĘDU? :: nie ponaglaj z odpowiedzią via PW!
Go to the top of the page
+Quote Post
Quadina
post 19.12.2010, 13:45:02
Post #10





Grupa: Zarejestrowani
Postów: 200
Pomógł: 38
Dołączył: 1.12.2010
Skąd: Wrocław

Ostrzeżenie: (0%)
-----


Przeczytałem ten temat i jestem w ciężkim szoku. Jak można nazywać cokolwiek błędem, mając FUNDAMENTALNE braki w wiedzy?


P.S. Po za tym od kiedy piszemy liczby zmiennoprzecinkowe w apostrofach? Chyba mnie coś ominęło...


--------------------
Warsztat: NetBeans 7.2 Beta, PHP, MySQL, PostgreSQL, Symfony (<=1.4), Diem, Java, Sieci neuronowe
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Wersja Lo-Fi Aktualny czas: 8.07.2025 - 19:42