0

How can i have rounded floating point numbers to be of equal values (so that == returns True) no matter what operations get applied on them (i want the end rounded results to be the same float). I have the following function:

def _round(f, n):
  x = f * pow(10, n)
  return truediv(int(x), pow(10, n))

but it still doesn't give me the same floating number. Is there a way to make a float (no matter how it has been calculated) to look always strictly the same, since they are being used in a dictionary as keys and any small change results in a KeyError.

Gautam Naik
  • 8,990
  • 3
  • 27
  • 42
  • did you try to use [`decimal`](https://docs.python.org/3/library/decimal.html?highlight=decimal#module-decimal) instead of `float`? – hiro protagonist Apr 23 '18 at 12:06
  • Your function does not round to the nearest value for the last decimal but rather truncate to only keep a given number of decimals. Is this the behavior you need? – sciroccorics Apr 23 '18 at 12:18
  • @sciroccorics Yes –  Apr 23 '18 at 12:55
  • Why are you using floating point numbers as dictionary keys? What value does the float represent? Generally, floating-point numbers are useful for measuring continuous values (e.g. physical measurements), not for discrete values (e.g. money, array indexes). Using a float as a dictionary key in the first place is a bit of a code smell that you may want a different type of value there anyway. – Daniel Pryden Apr 23 '18 at 12:56
  • @DanielPryden I am exactly using them for measuring continuous values, namely musical beats no matter how small they are (so for measuring time) –  Apr 23 '18 at 13:00
  • 2
    I would argue that musical beats aren't actually continuous, they're discrete. I think what you want is a rational number type: e.g. you want the `fractions` module. – Daniel Pryden Apr 23 '18 at 13:01
  • @ateymuri `fractions.Fraction` really is a great type for such things, and wholly underrated. Try it, and you won't look back. – user4815162342 Apr 23 '18 at 16:07

2 Answers2

0

I think if you can control the accuracy of your floats without jeopardizing your application you can do something like:

round(f, n)

instead of your code. Just round to the n-th digit of your float.

for example:

a = 2.12423
b = 2.12456
for i in range(1,5):
    print('round(a, {}) == round(b, {}) = {}'.format(i, i, round(a, i) == round(b, i)))

round(a, 1) == round(b, 1) = True
round(a, 2) == round(b, 2) = True
round(a, 3) == round(b, 3) = False
round(a, 4) == round(b, 4) = False

This answer also is really relevant.

Eypros
  • 5,370
  • 6
  • 42
  • 75
0

OK, if you need straight decimal truncation (i.e. without rounding up when last decimal is above 5) and use the result as a key for dictionnaries, I would suggest to convert the whole thing into strings. For instance:

def _round(f, n):
   return str(round(f, n+1))[:-1]

for n in range(9):
  print(n, '-->', _round(0.123456789, n))

Result:

0 --> 1.
1 --> 1.2
2 --> 1.23
3 --> 1.234
4 --> 1.2345
5 --> 1.23456
6 --> 1.234567
7 --> 1.2345678

If you need to perform some computation on the values afterwards, it's easy to convert back with float(x)

sciroccorics
  • 2,357
  • 1
  • 8
  • 21