'Python floating point is divisible by another floating point

Does anyone know a good way in Python to check if a number is divisible by another in floating point in python?

The first thing I tried was ...

3.5 % 0.1 == 0.0

But this returns False so then maybe

3.5 % 0.1 >= 1e-6 

But also False ... bummer ... it turns out that

3.5 % 0.1
>> 0.099999999924

So then this works:

LAMBDA = 1e-9
def is_divisible_by(x, y):
   m = x % y
   dy = abs(y - m)
   return m < LAMBDA or dy < LAMBDA

is_divisible_by(3.5, 0.1)

But this seems dangerous because I have to pick a LAMBDA. What about if y = LAMBDA / 2...

is_divisible_by(LAMBDA/2, (LAMBDA/2) + 1e-10)
>>> True

So then

  def is_divisible_by(x, y):
      l = y * 1e-2
      m = x % y
      dy = abs(y - m)
      return m < l or dy < l

  is_divisible_by(3.5 * 1e-10, 0.1 * 1e-10)
  >>> True

  is_divisible_by(0.21, 0.211)
  >>> True
  

Bummer.

Is there anyway to solve this without going down a massive rabbit hole?



Solution 1:[1]

Depending on the source of your floating point numbers, the decimal module might be useful.

>>> import decimal
>>> decimal.Decimal("3.5") % decimal.Decimal("0.1")
Decimal('0.0')

Solution 2:[2]

floating point numbers are "fuzzy". A good high-level mental model for floating point numbers is that they represent a small range of numbers (e.g 1.5 really means some number between 1.4999 and 1.5002). Because of this, there is not good way to check if one is divisible by another. Instead, to check if non-integer numbers are divisible by each other, you might want to use rational-type numbers. In python, there's a module for this, called Fraction. You can use it like this

from fractions import Fraction
a = Fraction(35,10) # 3.5
b = Fraction(1,10) # .1
a%b # evaluates to Fraction(0, 1)

Another answer mentioned the decimal python module. Fraction and decimal are interoperable.

from fractions import Fraction
from decimal import Decimal
a = Fraction(Decimal('3.5')) # 3.5
b = Fraction(Decimal('0.1)) # 0.1
a%b # evaluates to Fraction(0, 1)

I'm going to advocate for using Fraction as it is a bit more flexible

from fractions import Fraction
from decimal import Decimal
c = Decimal('1')
d = Decimal('.3')
c/d  # evaluates to Decimal('3.333333333333333333333333333')
c/d*d  # evaluates to Decimal('0.9999999999999999999999999999')
c = Fraction(c)
d = Fraction(d)
c/d # evaluates to Fraction(10, 3)
c/d*d # evaluates to Fraction(1, 1)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Peter DeGlopper
Solution 2