[PHP] floating point precisie

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Ritch
  • Registratie: December 1999
  • Laatst online: 19-09 15:46
Ik kwam een gek probleem tegen in m'n code. Logisch gezien moet het kloppen, maar dat deed het niet. Het kwam neer op deze hele simpele test.
PHP:
1
2
3
4
if ( 3 * $var == 4.05 )
{
  // doe iets
}
$var is een double van 1.35 en 3*1.35=4.05, oftewel de check is waar. Helaas denkt PHP daar anders over, 3*1.35 is geen 4.05 maar 4.05 en dan nog een heel klein beetje.
Correct: 3 * 1.35 - 4.05 = 0
PHP 4+5 (Linux): 3 * 1.35 - 4.05 = 8.881784197E-16
PHP 4+5+6snapshot (Windows): 3 * 1.35 - 4.05 = 8.8817841970013E-016
Bij PHP.net zeggen ze dan:
Floating point values have a limited precision. Hence a value might not have the same string representation after any processing. That also includes writing a floating point value in your script and directly printing it without any mathematical operations.
If you would like to know more about "floats" and what IEEE 754 is read this: http://docs.sun.com/source/806-3568/ncg_goldberg.html
Oftewel, je weet nooit of berekeningen goed gaan. Dat PHP geen taal is voor grote floating point getallen kan ik me voorstellen, maar zulke simpele berekeningen zouden toch goed moeten gaan? Als zoiets simpels al fout kan gaan, kan ik dus geen enkele berekening met een float in mn code nog vertrouwen.
De vraag is of ik PHP nog wel kan gebruiken voor bijv het genereren van facturen enzo, of moet ik soms overal bcmath functies gaan gebruiken?

Acties:
  • 0 Henk 'm!

  • sig69
  • Registratie: Mei 2002
  • Laatst online: 15:13
In java en c# heb je daar decimals voor. Misschien dat php dat ook heeft?

Roomba E5 te koop


Acties:
  • 0 Henk 'm!

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

NMe

Quia Ego Sic Dico.

Hier zijn in het verleden al meer dan genoeg topics over geweest. Geen enkele taal is precies met floating points. Voor meer precisie heb je andere types, zoals bijvoorbeeld doubles en decimals, alleen kent PHP die niet expliciet. Je zal dus in centen moeten gaan rekenen, of inderdaad bcmath moeten gebruiken.

'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!

  • hamsteg
  • Registratie: Mei 2003
  • Laatst online: 20-09 00:03

hamsteg

Species 5618

Een floating point, in welke taal dan ook, mag je nooit met een precieze waarde vergelijken.

Lees: twijfelachtige Tsjechische mirror waar -NMe- de echte PHP link heeft

Voor deze situatie gebruik: bccomp -- Compare two arbitrary precision numbers

[ Voor 15% gewijzigd door hamsteg op 30-05-2006 12:58 . Reden: Google results beter bekijken ;) ]

... gecensureerd ...


Acties:
  • 0 Henk 'm!

  • Haan
  • Registratie: Februari 2004
  • Laatst online: 16:33

Haan

dotnetter

Je kan dit toch ook oplossen door een kleine foutmarge toe te staan? Dus dan wordt het iets als
PHP:
1
2
3
4
5
6
<?
if ( (3 * $var >= (4.05-x) && (3 * $var <= (4.05+x) )
{
  // doe iets
}
?>

waarbij x dan bijvoorbeeld waarde 0.00001 heeft :)

Kater? Eerst water, de rest komt later


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 02:21

Janoz

Moderator Devschuur®

!litemod

Persoonlijk vind ik een afwijking van 0.[14 nullen]1 procent behoorlijk acuraat.

Floats kun je net met == vergelijken. Dat ligt aan de manier waarop een float in het geheugen wordt opgeslagen.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

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

NMe

Quia Ego Sic Dico.

hamsteggot schreef op dinsdag 30 mei 2006 @ 12:52:
Een floating point, in welke taal dan ook, mag je nooit met een precieze waarde vergelijken.

Lees: http://php.ftp.cvut.cz/manual/en/language.types.float.php
Waarom niet verwijzen naar de php.net manual in plaats van een twijfelachtige Tsjechische mirror ervan? :P
Voor deze situatie gebruik: bccomp -- Compare two arbitrary precision numbers
bcmath dus, die had de TS al gevonden. ;)

'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!

  • hawk88
  • Registratie: Augustus 2005
  • Laatst online: 15:36
als het niet met meer dan 2 cijfers achter de comma moet kan je het zo doen
[php]
$var = 1.35 ;
if ( round((3 * $var),3) == 4.05 )
{
// doe iets


}
[\php]

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

Nee dat kan helemaal niet. Floats werken niet met ons decimale stelsel, iets als 0.4 is dan ook niet te representeren door een float. Als jij 0.4 afrondt op 1 decimaal dan is het alsnog ~0.3999999761581421 (of 3355443 * 2-23 om precies te zijn)

[ Voor 95% gewijzigd door .oisyn op 30-05-2006 13:06 ]

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.


Acties:
  • 0 Henk 'm!

  • Ritch
  • Registratie: December 1999
  • Laatst online: 19-09 15:46
Ah ok, thx voor de uitleg!
Ik ga mn code nog maar es doorlopen of er nog meer stukken zijn waar mogelijk problemen zitten met floating point getallen.

Acties:
  • 0 Henk 'm!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
Twee cijfers doet me altijd vermoeden dat iemand met euros in plaats van centen rekent. 135 cent * 3 is namelijk 405 cent.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein

Pagina: 1