As a part of some unit testing code that I’m writing, I wrote the following function. The purpose of which is to determine if ‘a’ could be rounded to ‘b’, regardless of how accurate ‘a’ or ‘b’ are.
def couldRoundTo(a,b):
"""Can you round a to some number of digits, such that it equals b?"""
roundEnd = len(str(b))
if a == b:
return True
for x in range(0,roundEnd):
if round(a,x) == b:
return True
return False
Here’s some output from the function:
>>> couldRoundTo(3.934567892987, 3.9)
True
>>> couldRoundTo(3.934567892987, 3.3)
False
>>> couldRoundTo(3.934567892987, 3.93)
True
>>> couldRoundTo(3.934567892987, 3.94)
False
As far as I can tell, it works. However, I’m scared of relying on it considering I don’t have a perfect grasp of issues concerning floating point accuracy. Could someone tell me if this is an appropriate way to implement this function? If not, how could I improve it?
It depends. The given function will behave surprisingly if
bisn’t precisely equal to a value that would normally be obtained directly from decimal-to-binary-float conversion.For example:
This fails because the calculation of
0.3 / 3results in a slightly different representation than0.1and0.2 / 2(andround(0.123, 1)).Rule of thumb: if your calculation specifically involves decimal digits in any way, just use
Decimal, to avoid all the lossy base-2 round-tripping.In particular,
Decimalincludes a helper calledquantizethat makes this problem trivially easy: