[PHP] Vreemde uitkomst simpele berekening

Pagina: 1
Acties:
  • 163 views sinds 30-01-2008
  • Reageer

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Mexicanos
  • Registratie: Juli 2001
  • Niet online
Kan iemand mij vertellen waarom PHP mij de uitkomst verkeerde uitkomst geeft op de volgende simpele berekening. :?

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$TotBedrag = 1120;
$TotKorting = 448;
$TotAfboeking = 537.6;
$AlBetaald = 134.4;

$TeBetalen = $TotBedrag - $TotKorting - $TotAfboeking - $AlBetaald;

print $TeBetalen;

// Uitkomst volgens PHP: -2.84217094304E-014
// Uitkomst echt wereld: 0

// of nog simpeler:

print 1120 - 448 - 537.6 - 134.4;

[ Voor 16% gewijzigd door Mexicanos op 22-11-2005 15:22 . Reden: code in php veranderd ]


Acties:
  • 0 Henk 'm!

  • Nvidiot
  • Registratie: Mei 2003
  • Laatst online: 03-06 16:38

Nvidiot

notepad!

-2.842... * 10^-14 is zo goed als nul. Dat krijg je met floating-point getallen, die zijn niet exact. Wat je kunt doen is in centen rekenen (dus $AlBetaald = 13440).

What a caterpillar calls the end, the rest of the world calls a butterfly. (Lao-Tze)


Acties:
  • 0 Henk 'm!

  • StephanVierkant
  • Registratie: Mei 2003
  • Laatst online: 08-09 16:22
Ik zou me twee dingen kunnen voorstellen.

- Gebruik aanhalingstekens: $TotBedrag = "1120";
- Als je getallen gebruikt zonder decimalen, is het probleem er dan nog?

Acties:
  • 0 Henk 'm!

  • Mexicanos
  • Registratie: Juli 2001
  • Niet online
Dus PHP kan nooit een goede uitkomst geven bij berekeningen met float getallen?

Acties:
  • 0 Henk 'm!

  • AtleX
  • Registratie: Maart 2003
  • Niet online

AtleX

Tyrannosaurus Lex 🦖

Jawel, binnen de precisie die in php.ini is ingesteld (standaard 14 decimalen geloof ik).

Sole survivor of the Chicxulub asteroid impact.


Acties:
  • 0 Henk 'm!

  • Mexicanos
  • Registratie: Juli 2001
  • Niet online
Stephan4kant schreef op dinsdag 22 november 2005 @ 14:25:
Ik zou me twee dingen kunnen voorstellen.

- Gebruik aanhalingstekens: $TotBedrag = "1120";
- Als je getallen gebruikt zonder decimalen, is het probleem er dan nog?
Aanhalingstekens maken niks uit en bij getallen zonder decimalen gaat het wel goed.
AtleX schreef op dinsdag 22 november 2005 @ 14:27:
Jawel, binnen de precisie die in php.ini is ingesteld (standaard 14 decimalen geloof ik).
Maar ik kom toch niet buiten de precisie van PHP?

[ Voor 27% gewijzigd door Mexicanos op 22-11-2005 14:28 ]


Acties:
  • 0 Henk 'm!

  • Obliterator
  • Registratie: November 2000
  • Laatst online: 19-09 14:48
-2.84217094304E-014 is voor elk redelijk doel toch wel 0 hoor. Je kunt het afronden, maar rekenen in centen is een mooiere oplossing denk ik.

Acties:
  • 0 Henk 'm!

  • heuveltje
  • Registratie: Februari 2000
  • Laatst online: 20-09 18:24

heuveltje

KoelkastFilosoof

Toch vind ik het heel raar.
.6 - .4 zou toch .2 moeten opleveren.
en als php alles in 14 decimalen zou willen omrekenen dan word dat toch 0.2000000000000000.
hoe kan dat dan .200000001233124 worden ?
waar komen die "afrondingsfouten" dan vandaan :?

Heuveltjes CPU geschiedenis door de jaren heen : AMD 486dx4 100, Cyrix PR166+, Intel P233MMX, Intel Celeron 366Mhz, AMD K6-450, AMD duron 600, AMD Thunderbird 1200mhz, AMD Athlon 64 x2 5600, AMD Phenom X3 720, Intel i5 4460, AMD Ryzen 5 3600 5800x3d


Acties:
  • 0 Henk 'm!

  • Paul
  • Registratie: September 2000
  • Laatst online: 20-09 22:51
Mexicanos schreef op dinsdag 22 november 2005 @ 14:21:
Uitkomst volgens PHP: -2.84217094304E-014
Uitkomst echt wereld: 0
Aangezien het over bedragen gaat en we (in NL) niet kleiner rekenen dan met centen (benzinestations uitgezonderd :P) mag je 0,00000000000000284217094304 best gelijkstellen aan 0 :)

Rekenen met centen is wel een stuk nauwkeuriger (totdat je er renteberekeningen en zo op loslaat, omdat je dan met centen tusentijds aan het afronden bent), en tot aan 40 miljoen euro past het nog mooi in een int32 :)
heuveltje schreef op dinsdag 22 november 2005 @ 14:33:
Toch vind ik het heel raar.
.6 - .4 zou toch .2 moeten opleveren.
Dat zie je verkeerd. Er staat geen .2, net zomin als er .6 - .4 staat. Er staat .000000000000002, en er staat -.6 -.4 :)

[ Voor 21% gewijzigd door Paul op 22-11-2005 14:35 ]

"Your life is yours alone. Rise up and live it." - Richard Rahl
Rhàshan - Aditu Sunlock


Acties:
  • 0 Henk 'm!

  • Mexicanos
  • Registratie: Juli 2001
  • Niet online
Ik denk dat ik dan maar in centen moet gaan rekenen maar dit valt me wel een beetje tegen van php.

Ik heb zelf anders ook nog wel een grappige (maar omslachtige) oplossing gevonden:
Voer de berekening uit in MySQL :)

Maar ik hoop toch dat er iemand met een andere oplossing komt.

[ Voor 13% gewijzigd door Mexicanos op 22-11-2005 14:36 ]


Acties:
  • 0 Henk 'm!

  • Obliterator
  • Registratie: November 2000
  • Laatst online: 19-09 14:48
Op het einde een:
PHP:
1
value = round(value, 2);

Acties:
  • 0 Henk 'm!

  • PipoDeClown
  • Registratie: September 2000
  • Niet online

PipoDeClown

Izze Zimpell

volgens YAPF schijnt MySQL ook moeite te hebben met floats :P

God weet alles, want hij is lid van de Mosad. To protect your freedom i will take that away from you. Mijn drankgebruik heeft ernstig te lijden onder mijn gezondheid.


Acties:
  • 0 Henk 'm!

  • Grijze Vos
  • Registratie: December 2002
  • Laatst online: 28-02 22:17
Mexicanos schreef op dinsdag 22 november 2005 @ 14:34:
Ik denk dat ik dan maar in centen moet gaan rekenen maar dit valt me wel een beetje tegen van php.
Dit is niet php's schuld, dit is gewoon hoe computers rekenen met floating point getallen.

Op zoek naar een nieuwe collega, .NET webdev, voornamelijk productontwikkeling. DM voor meer info


Acties:
  • 0 Henk 'm!

  • Mexicanos
  • Registratie: Juli 2001
  • Niet online
Obliterator schreef op dinsdag 22 november 2005 @ 14:41:
Op het einde een:
PHP:
1
value = round(value, 2);
Dat werkt idd bij dit voorbeeld maar bij een aantal andere dingen waar ik mee bezig ben volgens mij niet.

Acties:
  • 0 Henk 'm!

  • kenneth
  • Registratie: September 2001
  • Niet online

kenneth

achter de duinen

Misschien moet je je verdiepen in het begrip floating point. Dit zijn gewoon allemaal eigenschappen van zo'n datatype.

Look, runners deal in discomfort. After you get past a certain point, that’s all there really is. There is no finesse here.


Acties:
  • 0 Henk 'm!

  • schoene
  • Registratie: Maart 2003
  • Laatst online: 17:04
sommige kommagetallen kunnen nu eenmaal niet binair voorgesteld worden. Probeer maar eens 0.5 in het binair getallenstelsel voor te stellen. Er wordt eigenlijk een benadering bijgehouden, en als je daar mee rekent kan je dus op het eerste gezicht vreemde resultaten verkrijgen.

Acties:
  • 0 Henk 'm!

  • Salandur
  • Registratie: Mei 2003
  • Laatst online: 14:41

Salandur

Software Engineer

schoene schreef op dinsdag 22 november 2005 @ 17:24:
sommige kommagetallen kunnen nu eenmaal niet binair voorgesteld worden. Probeer maar eens 0.5 in het binair getallenstelsel voor te stellen. Er wordt eigenlijk een benadering bijgehouden, en als je daar mee rekent kan je dus op het eerste gezicht vreemde resultaten verkrijgen.
0,5 is prima voor te stellen als 5 * 10 ^ -1: 0101:1111 (bij een mantise van 4 en een exponent van 4 in 2complements)

edit:
of natuurlijk 2 ^ -1

[ Voor 3% gewijzigd door Salandur op 22-11-2005 17:29 ]

Assumptions are the mother of all fuck ups | iRacing Profiel


Acties:
  • 0 Henk 'm!

  • Henk007
  • Registratie: December 2003
  • Laatst online: 06-04 00:29
Ik denk inderdaad dat TS zich verder moet verdiepen in de binaire representatie van floating points en de consekwenties daarvan voor afrondingsfouten.
Voorbeelden: 1, 2, 3, 4 , enz.

Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 21:01
Een IEEE float wordt altijd uitgedrukt in basis 2, dus het is alleen maar interessant of je 'm in het binaire stelsel kunt uitdrukken. 0,5 kan wel natuurlijk, maar iets simpels als 0,1 niet.

Acties:
  • 0 Henk 'm!

  • kenneth
  • Registratie: September 2001
  • Niet online

kenneth

achter de duinen

Je hebt natuurlijk ook precieze opslag. In .NET heb je bijvoorbeeld Decimal.

Look, runners deal in discomfort. After you get past a certain point, that’s all there really is. There is no finesse here.


Acties:
  • 0 Henk 'm!

  • PrisonerOfPain
  • Registratie: Januari 2003
  • Laatst online: 26-05 17:08
PipoDeClown schreef op dinsdag 22 november 2005 @ 14:42:
volgens YAPF schijnt MySQL ook moeite te hebben met floats :P
Mocht je er veel problemen mee hebben, kijk eens naar het DECIMAL data type voor je kolomen.

Acties:
  • 0 Henk 'm!

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

schoene schreef op dinsdag 22 november 2005 @ 17:24:
sommige kommagetallen kunnen nu eenmaal niet binair voorgesteld worden. Probeer maar eens 0.5 in het binair getallenstelsel voor te stellen.
euh, 0.1 bijvoorbeeld? :P
0.4 decimaal wordt wat moeilijker, het aantal bits dat je daarvoor nodig hebt is oneindig: 0.011001001001001001001001001001001001... enzovoorts.

[ Voor 7% gewijzigd door .oisyn op 22-11-2005 21:41 ]

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!

  • Borizz
  • Registratie: Maart 2005
  • Laatst online: 24-08 20:35
Je kan de BC Math library gebruiken van PHP, die geeft de door jou gewenste resultaten. BC Math rekent met string representaties van je floats.

If I can't fix it, it ain't broken.


Acties:
  • 0 Henk 'm!

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

Euh, de precisie blijft eindig hoor. Of wil je beweren dat 1/3 ineens wel met een string te representeren is?

.edit: ik zie nu trouwens dat ik je post iets te generiek opvat, voor prijzen werkt die library natuurlijk prima, maar dan kun je ook gewoon met ints werken. Desalniettemin is het niet de algemene oplossing voor afrondingsfouten

[ Voor 55% gewijzigd door .oisyn op 22-11-2005 21:49 ]

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!

  • Borizz
  • Registratie: Maart 2005
  • Laatst online: 24-08 20:35
.oisyn schreef op dinsdag 22 november 2005 @ 21:46:
Euh, de precisie blijft eindig hoor. Of wil je beweren dat 1/3 ineens wel met een string te representeren is?

.edit: ik zie nu trouwens dat ik je post iets te generiek opvat, voor prijzen werkt die library natuurlijk prima, maar dan kun je ook gewoon met ints werken. Desalniettemin is het niet de algemene oplossing voor afrondingsfouten
Daarom zei ik er ook bij dat het voor de TS de gewenste resultaten opleverde ;) , ik heb nooit gezegd dat het preciezer is!

If I can't fix it, it ain't broken.


Acties:
  • 0 Henk 'm!

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

Dan zou ik gewoon in centen rekenen, heb je ook niet het gedoe met allemaal functioncalls voor doodgewone berekeningen :)

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!

Verwijderd

kenneth schreef op dinsdag 22 november 2005 @ 17:41:
Je hebt natuurlijk ook precieze opslag. In .NET heb je bijvoorbeeld Decimal.
"precieze opslag"? uhh, dat zijn gewoon meer cijfers achter de komma....
En er wordt met machten gegoocheld 0.244= 244^x (ben niet goed in machten ;)) volgens de Decimal-beschrijving.

Wat betreft PHP zijn er genoeg alternatieven aangedragen.
De BCMath library, of werken met centen.

...

What every scientist should know about floating-point arithmetic :)

[ Voor 25% gewijzigd door Verwijderd op 22-11-2005 23:43 ]


Acties:
  • 0 Henk 'm!

  • kenneth
  • Registratie: September 2001
  • Niet online

kenneth

achter de duinen

Nouja, ik kan even niet op de term komen. Als je 0.244 opslaat in een float, dan staat er 0.24399999999998654, maar als je het opslaat in een decimal, dan staat er gewoon 0.244

Look, runners deal in discomfort. After you get past a certain point, that’s all there really is. There is no finesse here.


Acties:
  • 0 Henk 'm!

  • schoene
  • Registratie: Maart 2003
  • Laatst online: 17:04
schoene schreef op dinsdag 22 november 2005 @ 17:24:
sommige kommagetallen kunnen nu eenmaal niet binair voorgesteld worden. Probeer maar eens 0.5 in het binair getallenstelsel voor te stellen. Er wordt eigenlijk een benadering bijgehouden, en als je daar mee rekent kan je dus op het eerste gezicht vreemde resultaten verkrijgen.
die 0.5 was dus een typfout :) maar anderen hebben dus al goede voorbeelden gegeven over wat ik bedoel.

Acties:
  • 0 Henk 'm!

  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

Kommagetallen moet je in de meeste gevallen sowieso tussendoor afronden tot getallen met bijvoorbeeld 2 of 4 decimalen. Waarom?

Stel je voor dat je een programma hebt voor salarisadministratie en je wilt het totaal berekenen van alle medewerkers. Het salaris van een medewerker wordt ook opgebouwd uit X factoren waardoor er niet altijd een mooi getal uitkomt.

Als je nu het salaris per medewerker toont, rond je het af, want de gebruiker hoeft niet te zien dat het salaris 1452,234434484848484 is, maar die wil 1452,23 zien.

Het automatisch berekende totaal van alle salarissen dient altijd gelijk te zijn aan het zelf berekende totaal.

Is dit zo belangrijk zou je zeggen? Ja, want als een administratiefiguur alle zaken aan het narekenen is, wil je niet dat er afrondingsfouten in het totaal staan, want dat zijn getallen die hij nooit kan herleiden, simpelweg omdat het een computerfout is.

Dit wil overigens niet zeggen dat je al je waarden zomaar op twee decimalen moet afronden, maar je moet er zorgvuldig over nadenken welke schaal je gebruikt.

Als je voor het gemak in je code een percentage voorstelt als een getal van 0-1 dan is het waanzin om het op 2 decimalen af te ronden, want dat duidt er op dat je afrondt op geen decimalen. In zo'n geval zijn 4 decimalen gewenst, tewijl je functioneel gezien 2 decimalen nodig hebt.

Fat Pizza's pizza, they are big and they are cheezy


Acties:
  • 0 Henk 'm!

  • Henk007
  • Registratie: December 2003
  • Laatst online: 06-04 00:29
Opmerking bij de hier voorgestelde alternatieven (decimal en string arythmetics) is wel dat de performance dramatisch daalt, voorzover het rekenwerk een significant onderdeel van de applicatie is.
IEEE 745 floating point rekenen zit namelijk in alle CPU's van tegenwoordig ingebakken, de alternatieven niet, die worden softwarematig geëmuleerd.
Pagina: 1