Bedrag met 4 cijfers achter de komma; INTEGER of DECIMAL 8,4

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • TheNephilim
  • Registratie: September 2005
  • Laatst online: 21-05 15:48
Huidige situatie

Prijs van een product wordt in database (MySQL) opgeslagen als een INTEGER. Vervolgens ga ik er op de website (PHP) mee rekenen en bij presentatie deel ik het getal door 100. Uiteindelijk staat er dus netjes € 9,95 terwijl ik reken met 995 in hele centen.

Probleem

Anders dan de specificaties deden vermoeden, zijn er nu toch producten met een prijs waar meer dan 2 cijfers achter de komma voorkomen. Bijv. € 0,085.

Mogelijke oplossingen

A. Van INTEGER naar DECIMAL 8,4 en de prijs van de producten nu in de database vermenigvuldigen met 100. We rekenen dan gewoon met floats en bij presentatie hoeven we niet meer te delen door 100.

B. Zoals nu INTEGER laten en de prijs van de producten nu in de database vermenigvuldigen met 100. We rekenen dan met honderdste centen (toch?) en bij presentatie niet meer delen door 100, maar door 10.000.

Eigenlijk neig ik naar oplossing A, omdat B me erg raar in de oren klinkt en iets wat vergezocht lijkt. Toch vraag ik me af op ik bij oplossing A geen last ga krijgen van afrondingsfouten en dergelijke.

Er komen ordervoorbeelden uit dit systeem rollen en het bedrag hoeft niet afgerekend te worden. Het verschil in totaalbedragen met 4, ten opzichte van 2, cijfers achter de komma is bij hoge aantallen natuurlijk wel groot en moet eigenlijk wel gecorrigeerd worden.

Wat is de beste oplossing en zie ik wat over het hoofd?

[ Voor 3% gewijzigd door TheNephilim op 23-01-2017 11:24 ]


Acties:
  • 0 Henk 'm!

  • g0tanks
  • Registratie: Oktober 2008
  • Laatst online: 23:50

g0tanks

Moderator CSA
Als het uiteindelijk maar om één bedrag gaat dat je presenteert, waarom dan niet gewoon de onnodige decimalen wegknippen op het eind? Zo bljif je met de goede productprijzen rekenen.

Ultrawide gaming setup: AMD Ryzen 7 2700X | NVIDIA GeForce RTX 2080 | Dell Alienware AW3418DW


Acties:
  • +1 Henk 'm!

  • Rannasha
  • Registratie: Januari 2002
  • Laatst online: 22:52

Rannasha

Does not compute.

Ik zou voor oplossing A gaan, precies om de reden die je nu tegen bent gekomen: Als de mate van preciezie verandert dan moet je in een oplossing-B-scenario je hele tabel omzetten naar het nieuwe formaat en daarnaast ook nog eens je code aanpassen om de conversie terug naar Euro's goed te doen. Meer onderhoud, meer kans op fouten.

Het DECIMAL type slaat getallen op zonder de afrondfoutjes die een floating point type met zich meebrengt. Rekenen met DECIMAL waardes is dus exact, wat gunstig is als het gaat om geldbedragen. Daarnaast kun je een DECIMAL kolom altijd later wijzigen om extra precisie toe te voegen als dat in de toekomst nodig is. Dit is een enkele query om de tabel te wijzigen en dus veel simpeler dan de wijzigingen die je moet doen als je oplossing B toe past.

|| Vierkant voor Wiskunde ||


Acties:
  • +1 Henk 'm!

  • OnTracK
  • Registratie: Oktober 2002
  • Laatst online: 19:45
Persoonlijk zou ik gaan voor DECIMAL. Let wel even op dat DECIMAL 8,4 "in totaal" 8 cijfers heeft, waarvan 4 achter de komma, dus maar 4 vóór de komma. Dat wil nog wel eens verwarrend zijn. Als je tot 8 cijfers voor de komma en 4 cijfers achter de komma wil hebben moet je dus DECIMAL 12,4 gebruiken.

Not everybody wins, and certainly not everybody wins all the time.
But once you get into your boat, push off and tie into your shoes.
Then you have indeed won far more than those who have never tried.


Acties:
  • 0 Henk 'm!

  • TheNephilim
  • Registratie: September 2005
  • Laatst online: 21-05 15:48
g0tanks schreef op maandag 23 januari 2017 @ 11:29:
Als het uiteindelijk maar om één bedrag gaat dat je presenteert, waarom dan niet gewoon de onnodige decimalen wegknippen op het eind? Zo bljif je met de goede productprijzen rekenen.
Nee ik moet rekenen met 0,085 en niet met 0,08. Bij aantallen van 100 of 1000 zit daar nog wel een aardig verschil in qua totaalbedrag.
Rannasha schreef op maandag 23 januari 2017 @ 11:33:
Ik zou voor oplossing A gaan, precies om de reden die je nu tegen bent gekomen: Als de mate van preciezie verandert dan moet je in een oplossing-B-scenario je hele tabel omzetten naar het nieuwe formaat en daarnaast ook nog eens je code aanpassen om de conversie terug naar Euro's goed te doen. Meer onderhoud, meer kans op fouten.

Het DECIMAL type slaat getallen op zonder de afrondfoutjes die een floating point type met zich meebrengt. Rekenen met DECIMAL waardes is dus exact, wat gunstig is als het gaat om geldbedragen. Daarnaast kun je een DECIMAL kolom altijd later wijzigen om extra precisie toe te voegen als dat in de toekomst nodig is. Dit is een enkele query om de tabel te wijzigen en dus veel simpeler dan de wijzigingen die je moet doen als je oplossing B toe past.
Helder, maar na ophalen van die DECIMAL uit de MySQL database moet ik er nog wel mee rekenen in PHP. Daar zit ik weer met een float; levert dat geen problemen op qua precisie?
OnTracK schreef op maandag 23 januari 2017 @ 11:33:
Persoonlijk zou ik gaan voor DECIMAL. Let wel even op dat DECIMAL 8,4 "in totaal" 8 cijfers heeft, waarvan 4 achter de komma, dus maar 4 vóór de komma. Dat wil nog wel eens verwarrend zijn. Als je tot 8 cijfers voor de komma en 4 cijfers achter de komma wil hebben moet je dus DECIMAL 12,4 gebruiken.
Volgens mij heb ik genoeg aan die 4 voor en 4 na de komma, maar wellicht verstandig om hoger te gaan zitten inderdaad. Bedankt voor de tip!

Acties:
  • +1 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 24-05 00:52

.oisyn

Moderator Devschuur®

Demotivational Speaker

Rannasha schreef op maandag 23 januari 2017 @ 11:33:
Ik zou voor oplossing A gaan, precies om de reden die je nu tegen bent gekomen: Als de mate van preciezie verandert dan moet je in een oplossing-B-scenario je hele tabel omzetten naar het nieuwe formaat en daarnaast ook nog eens je code aanpassen om de conversie terug naar Euro's goed te doen. Meer onderhoud, meer kans op fouten.
Eens met het gebruiken van het juiste datatype in je database. DECIMAL is hier dus de juiste keuze.

Let dan vervolgens wel op de juiste afhandeling in PHP. De Mysql library zal zijn data teruggeven als strings, dus daar treden nog geen problemen op, maar als je er mee gaat rekenen worden ze geconverteerd naar float en verlies je precisie. De keuze is dan om ofwel BCMath te gebruiken, oftewel de boel in ints te houden in PHP.

Je kan wegkomen met een vermenigvuldiging met 10000 bij het uitlezen en een deling met 10000 bij het wegschrijven, daar een 64-bits floating point genoeg precisie heeft voor 15 significante decimale cijfers (voor bedragen onder de 10 miljard dus geen probleem :)). Let hierbij wel op een goede afronding (gebruik round() bij conversie naar int en sprintf() bij conversie naar string in 12.4 formaat)
Het DECIMAL type slaat getallen op zonder de afrondfoutjes die een floating point type met zich meebrengt. Rekenen met DECIMAL waardes is dus exact, wat gunstig is als het gaat om geldbedragen.
Hier wil ik even op inhaken. Rekenen in DECIMAL is helemaal niet exact. Ook in DECIMAL zal het niet mogelijk zijn om 1/3 op te slaan. Het verschil met float is dat menselijke invoer exact gerepresenteerd kan worden, omdat het een decimale representatie gebruikt ipv een binaire.

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:
  • +1 Henk 'm!

  • Rannasha
  • Registratie: Januari 2002
  • Laatst online: 22:52

Rannasha

Does not compute.

TheNephilim schreef op maandag 23 januari 2017 @ 11:44:
Helder, maar na ophalen van die DECIMAL uit de MySQL database moet ik er nog wel mee rekenen in PHP. Daar zit ik weer met een float; levert dat geen problemen op qua precisie?
Je kunt de BCMath extensie voor PHP gebruiken voor arbitrary-precision math: http://www.php.net/manual/en/ref.bc.php

Maar daarnaast kun je je afvragen of je echt last gaat krijgen van floating point fouten. De implementatie in PHP geeft 15~16 significante cijfers aan nauwkeurigheid bij eenvoudige operaties (optellen, vermenigvuldigen, enz...), dus zolang de bedragen daar niet in de buurt van komen zul je niet tegen problemen aanlopen. Als je de uitkomst van een berekening hergebruikt en dat vele malen doet, dan loop je het risico dat je uiteindelijk door opstapelende afrondfouten er een klein beetje naast gaat zitten. Maar dat is prima te voorkomen door na bepaalde tussenstappen in de berekening het bedrag weer af te ronden op de gewenste precisie.

|| Vierkant voor Wiskunde ||

Pagina: 1