1

I am an experienced R user and I am trying to learn Python3 on my own since a couple of days. The way Python handles floating-point numbers is really confusing for me at the beginning. For example,

print(1.1+2.2==3.3)

will return False. I know that I can solve this "problem" how Python interprets floating-point numbers by using the decimal module.

import decimal as d
print(d.Decimal("1.1")+d.Decimal("2.2")==d.Decimal("3.3"))

will return True and this is exactly what I wanted.

But how does this work with variables or other functions ? For example, I want to calculate the determinant of the following matrix:

import numpy as np
from numpy import linalg

A = np.array([[1,2],[3,4]])
Det_A = np.linalg.det(A)
print(Det_A)

The result is -2.0000000000000004 but I want the result to be exactly -2. How can I do this ?

Please excuse my imprecise language, I am not a computer scientist. Any advice is welcome.

Lars
  • 115
  • 3
  • 1
    you can use `round()` here – Ibrahim Jul 01 '21 at 18:51
  • 3
    See [Is floating point math broken?](https://stackoverflow.com/q/588004/5987) Short answer is, you can't. – Mark Ransom Jul 01 '21 at 18:52
  • 1
    `1.1+2.2 == 3.3` being `False` is a standard floating point issue. It's not at all specific to Python. If you tried it in C or any other language that uses IEEE floating point, you'd probably see the same thing. As a rule, it doesn't make sense to compare floating point numbers for equality. – Tom Karzes Jul 01 '21 at 18:53
  • 2
    I don't think floating point is the problem, nor do I think using the decimal package is what you want. The problem is that you aren't using floating point properly. In floating point, instead of comparing `a + b == c`, what you want is `abs(a + b - c) <= epsilon` for some small `epsilon`. Equality comparisons don't usually arise very often, but when they do, you need to allow for a margin of error. – Tom Karzes Jul 01 '21 at 18:55
  • Makes sense, thanks for your answer, – Lars Jul 01 '21 at 18:58
  • 1
    @TomKarzes there's a better alternative to `epsilon`: see [What is the best way to compare floats for almost-equality in Python?](https://stackoverflow.com/q/5595425/5987) – Mark Ransom Jul 01 '21 at 19:02
  • 1
    @MarkRansom Yes, that's a more accurate way to do it, and is scales with the magnitudes of the numbers. Whether or not it's needed depends on the range of values you're dealing with. – Tom Karzes Jul 01 '21 at 19:06
  • This isn't a problem with how "python handles floating point numbers" this is *how floating point numbers will always work* – juanpa.arrivillaga Jul 01 '21 at 19:56
  • Note that R is doing the same behind the scenes, it's just less precise when it comes to displaying the result – Sam Mason Jul 07 '21 at 09:51

2 Answers2

1

SciPy seems to be able to calculate the determinant more accurately than NumPy. For example:

import numpy as np
from scipy import linalg

A = np.array([[1,2],[3,4]], dtype=float)

print(np.linalg.det(A))  # => -2.0000000000000004
print(linalg.det(A))     # => -2.0

I'm not sure if this is true in general, but using SciPy versions seems to be preferred and hence it seems reasonable where possible. E.g. if you're making a Docker container and the only reason to pull in SciPy was to get a more accurate determinant then I wouldn't do it, but when working locally or if using more functionality then it's probably worth using SciPy.

Also note that R suffers from the same issues when using floating-point maths, for example I get FALSE back when entering 1.1 + 2.2 == 3.3 in R. This can be confirmed by calculating (1.1 + 2.2) - 3.3, in R this outputs:

4.440892e-16

while Python gives:

4.440892098500626e-16

These are the same values, it's just that Python is more precise at displaying the results.

Sam Mason
  • 15,216
  • 1
  • 41
  • 60
0

Would it be ok for your application to cast to integer? print(int(Det_A)) or to just print 2 digits after the decimal pointprint({:.2f}".format(Det_A))

MohamedA95
  • 36
  • 1
  • 5