2

I am using python 2.7.6. When I type this into the interpreter

>>> 0.135-0.027 0.10800000000000001 

Whereas it should be just

0.108 

This causes problem when comparing things, for example I want to compare

>>> 0.135-0.027 <= 0.108 False 

I want this to give answer as True. Do I have to use a special package that will handle floats properly? Is there a way to fix this another way? For example we can force floating division with

from __future__ import division 

Is there a similar solution to this problem?

8
  • 5
    Generally it is a bad idea to compare real numbers for equality in all computer languages because of the way floats are stored. You should allow for a tolerance, like rewriting your condition as abs(0.135-0.027 - 0.108)<1e-9 Commented Mar 10, 2014 at 17:15
  • 1
    @Selcuk He's not comparing for equality, he's doing greater(-or-equal)-than comparisons which are fine in general. In some cases, those can also benefit from a tolerance, but that's nowhere as universal as for strict equality. Commented Mar 10, 2014 at 17:26
  • possible duplicate of Python floating point Commented Mar 10, 2014 at 17:27
  • @delnan Yes, but the part it fails is the equality part. It is ok to use < or >, but is fail prone to use =, <= or >=. Commented Mar 10, 2014 at 17:30
  • FYI: docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html Commented Mar 10, 2014 at 17:31

2 Answers 2

2

There are various things you can do, but each has its own advantages and disadvantages.

The basic problem is that conversion from decimal to any finite binary representation involves rounding. If you were to use IEEE quadruple precision, for example, these cases would be rarer, but would still occur.

You could use a decimal library or an arbitrary precision library, but you may be unwilling to pay the cost in runtime for using them if you have to do trillions of these calculations.

In that case, you have to ask yourself the question, “How accurately do I really know these numbers?” Then you can consider, “Is it permissible for 0.135-0.027 <= 0.108 to be considered true?” In most cases, the answer to these is “not that accurately” and “yes” and your problem is solved. You might be uncomfortable with the solution, but it's swings and roundabouts: the errors are going to occur “both ways” (in the sense that it sometimes the comparison is going to fail when it should succeed, and sometimes it is going to succeed when it should fail).

If failing one way is perfectly OK, but failing the other way is absolutely not, you can either change the rounding mode of your hardware (to suit the bias you want), or you can add/subtract a ULP (to suit the bias you want).

For example, consider the following (sorry for the C, but I'm sure you get the idea):

double add_ulp(double x) { union { double x; unsigned sign : 1; unsigned expo : 11; unsigned long mant : 52; } inc; inc.x = x; inc.mant = 0; if (inc.expo >= 52 ) { inc.expo -= 52; return x+inc.x; } return x; } 

You can use this like this:

if( x-y <= add_ulp(z) ) { // ... } 

And it will give you the answer you want in your case, but it will bias your results in general. If that's the bias you want, it isn't a problem, but if it's not, it's worse than the problem you currently have.

Hope this helps.

Sign up to request clarification or add additional context in comments.

Comments

-1

This might help: https://pythonhosted.org/bigfloat/

You can control the precision with this as well.

4 Comments

How is this superior to the standard library's decimal module?
mostly the level of precision. You can choose to use any of the modules you like.
The decimal module is the correct solution to this problem (since the problem is a side-effect of binary floating point). bigfloat, mpmath, and gmpy2 all provide arbitrary precision binary floating point. They'll provide more precision but are still not able to represent all decimal numbers exactly.
I am aware that I can solve this problem with using a library, I was wondering if I can avoid doing so

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.