[PHP] Afrondingsfout met round()?

Pagina: 1
Acties:

Onderwerpen


Verwijderd

Topicstarter
Beste Tweakers,

Ik ben zojuist achter een vreemd probleem met de afronding in PHP gekomen. Ik gebruik hiervoor de functie round(). Dit geeft de volgende resultaten:

round(30.925, 2) -> 30.93
round(31.925, 2) -> 31.93
round(32.925, 2) -> 32.92
round(33.925, 2) -> 33.92


round(511.925, 2) -> 511.93
round(512.925, 2) -> 512.92

Ik heb een scriptje gemaakt dat van 0 tot 10.000 gaat controleren of er wordt afgerond op .92 of .93 (als ik .925 achter de komma heb), vreemd genoeg gaat dit dus soms mis (want het moet .93 zijn!).

Het gaat het dus fout vanaf 32.925, vervolgens weer vanaf 512.925.

Enig idee waar deze afrondingsfout vandaan komt?

Machine: FreeBSD, PHP 5.2.5


Hartelijk dank!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Kijk even naar Bankers Wikipedia: Rounding

Overigens is de mode gewoon een parameter:
float round ( float $val [, int $precision = 0 [, int $mode = PHP_ROUND_HALF_UP ]] )
...
mode
One of PHP_ROUND_HALF_UP, PHP_ROUND_HALF_DOWN, PHP_ROUND_HALF_EVEN, or PHP_ROUND_HALF_ODD.
[edit]
Kolere; heb ik je post even gaar/half gelezen zeg :X My bad. Hmmm, maar dan zie ik het ook even niet helemaal waar 't precies vandaan komt.

[ Voor 79% gewijzigd door RobIII op 24-09-2009 14:51 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Verwijderd

Topicstarter
RobIII schreef op donderdag 24 september 2009 @ 14:47:
Kolere; heb ik je post even gaar/half gelezen zeg :X My bad.
Geen punt, maar dat is dus inderdaad waar het mis gaat...

Waarom wordt round(31.925, 2) -> 31.93 en round(32.925, 2) -> 32.92?


gr,

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Dit komt denk ik omdat doubles niet exact zijn. Oplossing: ietsje erbij optellen.
PHP:
1
 echo round(512.9250001, 2); // 512.93

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Het zal inderdaad wel iets met floats van doen hebben (Getallen en talstelsels FAQ - Floats en afronding).

Edit: C# doet 't ook zo, alleen ligt het omslagpunt op een andere plek:
63,92
64,93
...
255,93
256,92
Maar dat zal wel aan de preciezie van de soort float liggen in PHP/C#

[ Voor 44% gewijzigd door RobIII op 24-09-2009 14:58 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


  • Bas Jansen
  • Registratie: Juni 2000
  • Laatst online: 13-06 09:15
In de PHP manual op http://nl3.php.net/manual/en/language.types.float.php staat een hele grote waarschuwing dat doubles en floats niet precies zijn en daar staat ook welke functies je dan wel kunt gebruiken als hoge precisie gewenst is.

Wat je trouwens ook nog zou kunnen proberen:

PHP:
1
2
$a = 32.925;
echo intval($a*100)/100;

[ Voor 18% gewijzigd door Bas Jansen op 24-09-2009 14:57 ]


  • gertvdijk
  • Registratie: November 2003
  • Laatst online: 11:40
En zoals ook bij het commentaar van de round()-functie in de online PHP manual:
the result of this function always depends on the underlying C function. There have been a lot of compiler bugs and floating-point precission problems involving this function. Right now the following code:

<?php
echo round(141.075, 2);
?>

returns:

141.07

on my machine.
So never really trust this function when you do critical calculations like accounting stuff!
Instead: use only integers or use string comparisons.

Kia e-Niro 2021 64 kWh DynamicPlusLine. See my GitHub and my blog for articles on security and other stuff.


  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
gertvdijk schreef op donderdag 24 september 2009 @ 15:01:
En zoals ook bij het commentaar van de round()-functie in de online PHP manual:

[...]
In dat commentaar word 99 v/d 100 keer meer onzin dan iets anders verkocht. Het is geen bug maar de consequentie van 't werken met floats. Ik ben niet héél bekend met PHP en weet dus niet welke "soort" floats er onderwater gebruikt worden, maar vreemd is het niet en zéér waarschijnlijk ook geen bug.

[ Voor 18% gewijzigd door RobIII op 24-09-2009 15:04 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

Bas Jansen schreef op donderdag 24 september 2009 @ 14:55:
Wat je trouwens ook nog zou kunnen proberen:

PHP:
1
2
$a = 32.925;
echo intval($a*100)/100;
Dat gaat je niet helpen, bovendien rond je nu altijd af richting 0.
RobIII schreef op donderdag 24 september 2009 @ 15:02:
[...]

In dat commentaar word 99 v/d 100 keer meer onzin dan iets anders verkocht. Het is geen bug maar de consequentie van 't werken met floats.
En het stomme is, als je een poster terecht wijst dan wordt dat weggemoderate. Is mij nu al 3x overkomen. 8)7

[ Voor 39% gewijzigd door .oisyn op 24-09-2009 15:04 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
.oisyn schreef op donderdag 24 september 2009 @ 15:02:
En het stomme is, als je een poster terecht wijst dan wordt dat weggemoderate. Is mij nu al 3x overkomen. 8)7
offtopic:
Heb ik ook wel eens geprobeerd maar ik heb na 2x de moed opgegeven en hoop dat ze lekker in hun eigen sop gaar koken :P
Ik heb 't al vaker gezegd maar ik snap sowieso niet dat ze al die onzin "integraal" in hun documentatie willen hebben. Het richt meer kwaad uit dan goed :X Laat gebruikers dan gewoon op een forum ofzo reageren/posten en neem zinnige zaken alsnog over in de documentatie als dat gewenst is.

[ Voor 11% gewijzigd door RobIII op 24-09-2009 15:07 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Ik zag een paar dagen geleden een poster op TheDailyWTF die het zaakje even mooi uitwerkt:
http://thedailywtf.com/Comments/Round_and_Round.aspx#112310

Zie ook: Wikipedia: IEEE 754-2008

[ Voor 23% gewijzigd door NMe op 24-09-2009 15:26 ]

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Verwijderd

RobIII schreef op donderdag 24 september 2009 @ 14:53:
Het zal inderdaad wel iets met floats van doen hebben (Getallen en talstelsels FAQ - Floats en afronding).

Edit: C# doet 't ook zo, alleen ligt het omslagpunt op een andere plek:

[...]

Maar dat zal wel aan de preciezie van de soort float liggen in PHP/C#
In C# gebruik je een decimal als je precisie wilt, toch? Zou er ook zo iets voorhanden zijn in PHP (Ik weet 't niet)?

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Verwijderd schreef op donderdag 24 september 2009 @ 15:56:
In C# gebruik je een decimal als je precisie wilt, toch?
Dat hangt er vanaf wat voor precisie je wil.Er zijn niet voor niets floats/doubles/decimals/whatnot's ;)
Verwijderd schreef op donderdag 24 september 2009 @ 15:56:
Zou er ook zo iets voorhanden zijn in PHP (Ik weet 't niet)?
AFAIK niet, maar ik ben geen PHP expert.

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

RobIII schreef op donderdag 24 september 2009 @ 15:57:
[...]

AFAIK niet, maar ik ben geen PHP expert.
http://nl3.php.net/manual/en/ref.bc.php

Maar dan denk ik dat je beter kan kijken naar de standaardoplossingen (getallen in centen/honderdste centen als integer opslaan) aangezien BCMath hiervoor gebruiken redelijk overkill is. :P

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • DeepFreeze.NL
  • Registratie: April 2006
  • Laatst online: 02-03 08:01
Ik had laatst een soortgelijk probleem met de afronding in PHP. Ik moest een berekening maken waarin met veel decimalen achter de komma werd gewerkt. Het resultaat van de berekening had heel soms een verschil van enkele centen die acceptabel waren, dus ik heb het er uiteindelijk min of meer bij gelaten zoals het was (round met 2 decimalen).

Toch na het lezen van jou topic ben ik weer even snel opzoek gegaan om een mogelijke oplossing te vinden, bcmath/bcscale lijkt inderdaad een oplossing te bieden. Wellicht dat deze functie een oplossing bied.
Pagina: 1