Python: a can be rounded to b in general

As part of some unit testing code that I write, I wrote the following function. The purpose of this is to determine whether it is possible to round “a” to “b”, regardless of how accurate “a” or “b” is.

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 is some function output:

 >>> 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, this works. However, I am afraid to rely on this, given that I do not have a perfect understanding of issues regarding floating point precision. Can someone tell me if this is suitable for implementing this feature? If not, how can I improve it?

+7
python floating-point rounding
source share
4 answers

Can someone tell me if this is suitable for implementing this feature?

It depends. This function will behave surprisingly if b not exactly equal to the value that is usually obtained directly from decimal to binary-float conversion.

For example:

 >>> print(0.1, 0.2/2, 0.3/3) 0.1 0.1 0.1 >>> couldRoundTo(0.123, 0.1) True >>> couldRoundTo(0.123, 0.2/2) True >>> couldRoundTo(0.123, 0.3/3) False 

This fails because calculating 0.3 / 3 leads to a slightly different presentation than 0.1 and 0.2 / 2 (and round(0.123, 1) ).

If not, how can I improve it?

Rule of thumb: if your calculation specifically includes decimal digits in any way, just use Decimal to avoid circular disconnection with base-2 losses.

In particular, Decimal includes a quantize helper, which makes this problem trivially easy:

 from decimal import Decimal def roundable(a, b): a = Decimal(str(a)) b = Decimal(str(b)) return a.quantize(b) == b 
+3
source share

One way to do this:

 def could_round_to(a, b): (x, y) = map(len, str(b).split('.')) round_format = "%" + "%d.%df"%(x, y) return round_format%a == str(b) 

First we take the number of digits before and after the decimal number in x and y. Then we build a format such as %x.yf Then we send a to the format string.

 >>> "%2.2f"%123.1234 '123.12' >>> "%2.2f"%123.1264 '123.13' >>> "%3.2f"%000.001 '0.00' 

Now all that remains is comparing the strings.

+1
source share

The only thing I'm afraid of is converting strings to floating points when interpreting floating point literals (as in http://docs.python.org/reference/lexical_analysis.html#floating-point-literals ). I don't know if there is any guarantee that the floating point literal will evaluate the floating point number that is closest to the given string. This section is a place in the specification where I would expect such a guarantee.

For example, Java is much more specific about what to expect from a string literal. From the documentation of Double.valueOf (String) :

[...] [argument] is considered as representing the exact decimal value in the usual "computerized scientific notation" or as the exact hexadecimal value; this exact numeric value is then conceptually converted to an "infinitely accurate" binary value, which is then rounded to enter double using the usual rounding rule to the nearest IEEE 754 floating point arithmetic rule [...]

If you can't find such a guarantee in the Python documentation, you might be lucky because some of the previous floating point libraries (which Python can rely on) only convert the string to a floating point number nearby, not the best available.

Unfortunately, it seems to me that neither round , nor float , nor the specification for floating point literals give you any useful guarantee.

0
source share

If you intend to check whether the round function will be rounded to the target, then you are right. Otherwise (what else is the goal?), If in doubt, you should use the decimal module

0
source share

All Articles