Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> [PHP] Złe zaokrąglanie, Funkcja round() wyczynia cuda.
msulik
post 25.08.2005, 14:58:44
Post #1





Grupa: Zarejestrowani
Postów: 83
Pomógł: 0
Dołączył: 31.03.2002
Skąd: Toruń

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


Witam. Nie siedzę w bugach php ani innych takich wynalazkach, więc może robię wiele hałasu o nic.

Mianowicie mamy sobie liczbę netto * vat = brutto, tzn 371.311475 * 1.22 = 452.9999995 (szesc dziewiatek i piątka). Zaokrąglenie do 6 miejsc po przecinku powinno dac 453. I tak sie prawie dzieje:
  1. <?php
  2. echo round(452.9999995, 6); // Daje 453
  3.  
  4. // Ale juz np.
  5. echo round(371.311475 * 1.22, 6);
  6. // powinno dawac teoretycznie to samo, czyz nie?
  7.  
  8. // Czesciowe rozwiazanie tego problemu, to dodanie 001 na koncu liczby netto:
  9. echo round(371.311475001 * 1.22, 6); // i teraz jest ok - daje 453
  10. ?>


Podobny problem z tymi zerami na koncu mam w MySQL:
  1. SELECT round(371.311475 * 1.22, 6), round(371.311475000001 * 1.22, 6)

To daje nam:
452.999999 | 453

Na chlopski rozum to bez sensu. W szkole uczyli mnie, że jak się zaokrągla do N miejsc po przecinku, to patrzy się nie dalej jak N+1.

Czy ktos moze mi to wyjasnic jak pastuch krowie? smile.gif


--------------------
misiu | chór

"Zdeterminowany programista potrafi stworzyć fatalny kod w każdym języku"
Allen Holub
Go to the top of the page
+Quote Post
Seth
post 26.08.2005, 00:05:17
Post #2





Grupa: Przyjaciele php.pl
Postów: 2 335
Pomógł: 6
Dołączył: 7.03.2002

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


Wyglada na to, ze to nie jest blad php:

http://binarychoice.pl/_images/vs_round.gif
biggrin.gif
Go to the top of the page
+Quote Post
NuLL
post 26.08.2005, 00:14:10
Post #3





Grupa: Zarejestrowani
Postów: 2 262
Pomógł: 21
Dołączył: 3.05.2004
Skąd: Sopot, Krakow, W-wa

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


Hehe - to tak zawsze jest z VAT-em.


--------------------
Javascript, Coffeescript, Node.js, Mongo, CouchDb, chmury, workery & inne bajery - zycie jest zbyt krotkie aby miec nudna prace :)
Go to the top of the page
+Quote Post
Marusz
post 26.08.2005, 00:22:49
Post #4





Grupa: Zarejestrowani
Postów: 191
Pomógł: 0
Dołączył: 16.05.2003
Skąd: POLAND

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


No dobra... ale co powiecie na to:
  1. <?php
  2.  
  3. $vA = 452.9999995;
  4. $vB = 371.311475;
  5. $vV = 1.22;
  6.  
  7. $vZ = $vB*$vV;
  8.  
  9. echo $vA . "n";
  10. echo $vZ . "n";
  11.  
  12. if ( $vA == $vZ )
  13. {
  14.  
  15. echo "OKn";
  16.  
  17. }
  18. else 
  19. {
  20.  
  21. echo "AMOKn";
  22.  
  23. }
  24.  
  25. ?>


Output:
Cytat
452.9999995
452.9999995
AMOK


Ten post edytował Marusz 26.08.2005, 00:24:57


--------------------
Go to the top of the page
+Quote Post
NuLL
post 26.08.2005, 00:57:58
Post #5





Grupa: Zarejestrowani
Postów: 2 262
Pomógł: 21
Dołączył: 3.05.2004
Skąd: Sopot, Krakow, W-wa

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


A czy liczby porównywane zgadzają się binarnie questionmark.gif snitch.gif Bo tu mogą być ucięte.


--------------------
Javascript, Coffeescript, Node.js, Mongo, CouchDb, chmury, workery & inne bajery - zycie jest zbyt krotkie aby miec nudna prace :)
Go to the top of the page
+Quote Post
dr_bonzo
post 26.08.2005, 10:32:44
Post #6





Grupa: Przyjaciele php.pl
Postów: 5 724
Pomógł: 259
Dołączył: 13.04.2004
Skąd: N/A

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


Pewnie jest to zwiazane ze sposobem przechowywania liczb przez php

  1. <?php
  2. print( round( round(371.311475 * 1.22, 7), 6 ) . '<br />' );
  3. ?>

^^^Wydaje sie dzialac.


--------------------
Nie lubię jednorożców.
Go to the top of the page
+Quote Post
NuLL
post 26.08.2005, 10:36:11
Post #7





Grupa: Zarejestrowani
Postów: 2 262
Pomógł: 21
Dołączył: 3.05.2004
Skąd: Sopot, Krakow, W-wa

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


Pewnie tak smile.gif

Gdyby wykorzystać funkcje kalkulatora binarnego wyniki byłyby dobre.


--------------------
Javascript, Coffeescript, Node.js, Mongo, CouchDb, chmury, workery & inne bajery - zycie jest zbyt krotkie aby miec nudna prace :)
Go to the top of the page
+Quote Post
popo
post 26.08.2005, 20:46:43
Post #8





Grupa: Zarejestrowani
Postów: 85
Pomógł: 0
Dołączył: 15.07.2005

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


liczby rzeczywiste sa przechowywane (nie tylko w php) jako cecha i mantysa co w polaczeniu z ograniczona dlugoscia slowa binarnego (zalezne od jezyka i procesora) powstaja bledy zaokraglen i nie jest to wada php tylko tego ze komputery pracuja w systemie binarnym o ograniczonej precyzji obliczen jesli moge cos zasugerowac to przy liczbach z okreslonego przedzialu mozna zapisywac je w bazie jako staloprzecinkowe typ DECIMAL powinno toto nieco polepszyc sytuacje co do php to
Cytat
Precyzja liczb zmiennoprzecinkowych

Jest oczywiste, że nawet proste ułamki dziesiętne, takie jak 0.1 lub 0.7, nie mogą zostać skonwertowane na ich dwójkowe odpowiedniki bez niewielkiej straty dokładności. Może to powodować pewne problemy: na przykład wyrażenie floor((0.1+0.7)*10) zwykle ma wartość 7, zamiast oczekiwanej 8, gdyż wewnętrzna reprezentacja tego wartości to liczba 7.9999999999....

Powiązane jest to z faktem, że dla pewnych ułamków zwykłych nie istnieje skończone rozwinięcie dziesiętne. Na przykład 1/3 w reprezentacji dziesiętnej ma wartość 0.3333333. . ..

Dlatego nigdy nie należy wierzyć liczbom zmiennoprzecinkowym do ostatniej cyfry i nigdy nie należy wykonywać operacji porównania na stwierdzenie równości. Do operacji na liczbach zmiennoprzecinkowych o naprawdę dużej precyzji należy użyć biblioteki BCMath lub funkcji gmp.

cytat z manuala smile.gif
http://php.net.pl/manual/pl/language.types...float-precision
Go to the top of the page
+Quote Post
TomASS
post 26.08.2005, 22:19:49
Post #9





Grupa: Zarejestrowani
Postów: 1 660
Pomógł: 13
Dołączył: 9.06.2004
Skąd: Wrocław i okolice

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


Zgadza się, komputer (a właściwie system) przetrzymuje liczby zmiennoprzecinkowe (i nie tylko) jako pewne, bardzo dokładne (ale zawsze niedokładne tongue.gif ) PRZYBLIŻENIE i z tąd mogą pochodzić te błędy.


--------------------
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: 16.07.2025 - 14:28