1

why does a simple python calculation give a different result than same calculation in PHP or pocket-calculator?

tmp = (50.73 / 120) * 20

in python3 tmp now is 8.45499999999 in php and other calculators it leads to 8.455 (without any manual rounding)

my problem here is that i need to round (commercial rounding) the tmp variable with 2 decimal points and this leads in python3 to 8.45 which is not correct. commercially rounded 8.455 would be 8.46

Jack
  • 59
  • 7
  • 1
    It does it properly, it gives more decimal places than a normal calculator as it can calculate it. – Tommy Lawrence Sep 06 '19 at 07:42
  • @TommyLawrence thats not the problem, 8.455 is the exact solution, it is not rounded, it is, as Julien suggested, a problem of float math. – Adirio Sep 06 '19 at 07:44
  • Oh, ok, I'll check out in python to see if It does it on mine to then. – Tommy Lawrence Sep 06 '19 at 07:48
  • If you work with currency, you could work with integers for cents instead of floats for dollars. – Eric Duminil Sep 06 '19 at 07:54
  • @Adirio: and what can i do to get the correct result? i agree that the lower solutions with round do not work in all cases – Jack Sep 06 '19 at 07:57
  • @Jack I added a solution that does work. – Adirio Sep 06 '19 at 08:04
  • @EricDuminil I would suggest working with `decimal.Decimal` if you are working with currencies as working with integer cents may also cause some troubles when divisions give float results that you need to round. `decimal.Decimal` should be always safe. – Adirio Sep 06 '19 at 08:09
  • The rounding was subtly but noticably changed from python2 to python 3 and dous NOT work now like in other languages and especially not as one might expect! – U. W. Sep 06 '19 at 08:56

1 Answers1

0

Please use decimal.Decimal instead of float:

from decimal import Decimal

Decimal("50.73") / Decimal(120) * Decimal(20)

If 50.73 is not a value you input, use decimal.Decimal to compute it. If it is a number you input from somewhere, just transform it inot string before creating the decimal, as Decimal(50.73) will present the same problems as floats.

Adirio
  • 5,040
  • 1
  • 14
  • 26
  • Sorry, but I don't think it works either. see `Decimal(1) / Decimal(3)` – Eric Duminil Sep 06 '19 at 08:24
  • @EricDuminil It does work. You must set the precission. By default it is 28 decimal places, thats why you are seeing `Decimal('0.3333333333333333333333333333')` but if you need a different one you can specify more with `decimal.getcontext().prec = 7` – Adirio Sep 06 '19 at 08:28
  • I don't think it can work for every example. There's an infinity of rationals which cannot be represented by decimals. – Eric Duminil Sep 06 '19 at 08:49
  • Also, you'd need to use [`ROUND_HALF_UP`](https://stackoverflow.com/questions/33019698/how-to-properly-round-up-half-float-numbers-in-python) in order to get commercial rounding. It fails with `Decimal(1) / Decimal(8)` otherwise. – Eric Duminil Sep 06 '19 at 09:00
  • `decimal.getcontext().rounding = decimal.ROUND_HALF_UP` as you suggested would correct that. It is something you need to do once for all your code so not that big of a problem. – Adirio Sep 06 '19 at 09:10
  • It's dangerous to set precision to `7` only. `Decimal(23998562) / Decimal(16221)` comes out as `Decimal('1479.475')` instead of `1479.4748782442514`. – Eric Duminil Sep 06 '19 at 12:07
  • @EricDuminil that depends on the usage. If you are computing euros and you know the highest amount you are going to compute is under a hundred thousand euros, a precission of 7 is all you need with the correct rounding method. What it has to be noticed is that 7 is the precission not the number of decimals. `99 999.99` has a precission of 7. – Adirio Sep 09 '19 at 09:30