0

I have two float values, I would like to subtract them and compare the result with another value in an if statement. Problem, I didn't manage to have the expected result. I tried to use Decimal module.

from decimal import Decimal, getcontext    
getcontext().prec = 3
value_1 = 60.32
value_2 = 59.72
condition = 0.6

sub = Decimal(value_1) - Decimal(value_2)

But,

sub <= condition
FALSE

sub <= Decimal(condition)
FALSE
NCall
  • 113
  • 6
  • 1
    Hi, could you please add some more context to your question? For instance, what is the 'Decimal' function you are calling? Is it your implementation or does it belong to an imported module? – DLM May 07 '21 at 08:17
  • 1
    Sorry, I edited my post – NCall May 07 '21 at 08:23

1 Answers1

1

This answer explains why this question is a dupe of Is floating point math broken?.


If you use

 k = Decimal(0.6)

and inspect k you get:

is floating math broken

This is a case of "Is floating math broken":

  • the number 0.6 is first converted to a float (wich gives the nearest float-approximation)
  • the float is passed on to the Decimal constructor wich dutifully constructs a Decimal that is just a little bit smaller then the 0.6 originally put in your source code.

You can avoid this by providing a string of your number to the decimal constructor instead to bypass the "float"-conversion.

Inspecting

value_1 = 60.32
value_2 = 59.72
sub = Decimal(value_1) - Decimal(value_2)

leads to :

exactly 0.6

which is exactly 0.6. As k is now slightly less then 0.6 your test of sub <= k returns False.

You can use k = Decimal("0.6") to get a decimal value that is exactly 0.6.

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
  • (or in your case: `sub <= Decimal(str(condition))` - as str() on the float will give you the approximated 0.6 as string back) – Patrick Artner May 07 '21 at 08:37
  • While floating-point rounding is involved here, this answer fails to state that the numerals in the source code are converted to binary floating-point before the `Decimal` constructor converts them to decimal. So what is converted to decimal is the binary floating-point value, not the original numeral. And one solution to this is to change the variables to strings, such as `value_1 = '60.32'`, so the numerals are retained and passed to the constructor. This is a key point in this question, so it should not be marked as a duplicate of the floating-point black hole. – Eric Postpischil May 07 '21 at 11:47
  • @EricPostpischil I still think this is a dupe but I adjusted the answer with the points you made in the comment. Decimal works just fine in that case, the real cause is using a float to create the decimal and that error boils down to floating math broken... – Patrick Artner May 07 '21 at 12:13