curious_cosmo
curious_cosmo

Reputation: 1214

Rounding in Python to avoid machine precision errors

I would like to check if a float is a multiple of another float, but am running into issues with machine precision. For example:

t1 = 0.02
factor = 0.01
print(t1%factor==0)

The above outputs True, but

t2 = 0.030000000000000002
print(round(t2,5)%factor==0)

This outputs False. At some points in my code the number I am checking develops these machine precision errors, and I thought I could fix the issue simply by rounding it (I need 5 decimal places for later in my code, but it also doesn't work if I just round it to 2 decimal places).

Any ideas why the above check round(t2,5)%factor==0 doesn't work as expected, and how I can fix it?

Upvotes: 1

Views: 828

Answers (3)

Zaid Al Shattle
Zaid Al Shattle

Reputation: 1534

Generally, floats in Python are... messed up, for the lack of a better word. And they can act in very unexpected ways. (You can read more about that behaviour here.)

For your goal however, a better way is this:

t2 = 0.03000003
factor = 0.01
precision = 10000  # 4 digits
print(int(t2*precision)%int(factor*precision)==0)

Moving the maths to an integer-based calculation solves most of those issues.

Upvotes: 0

manu190466
manu190466

Reputation: 1603

You should use the decimal module. The decimal module provides support for fast correctly-rounded decimal floating point arithmetic.

import decimal
print( decimal.Decimal('0.03') % decimal.Decimal('0.01') == decimal.Decimal('0') )

Gives :

True

Upvotes: 2

Kyle Parsons
Kyle Parsons

Reputation: 1525

It doesn't work as expected because checking floats for equality almost never works as expected. A quick fix would be to use math.isclose. This allows you to adjust your tolerance as well. Remember that when doing arithmetic mod r, r is equivalent to 0, so you should check if you're close to 0 or r.

import math

t1 = 0.02
factor = 0.01
res = t1 % factor
print(math.isclose(res, 0) or math.isclose(res, factor))

This is pretty quick and dirty and you will want to make sure your tolerances are working correctly and equivalently for both of those checks.

Upvotes: 3

Related Questions