What is the best way to compare floats for almost-equality in Python?

后端 未结 15 1554
旧时难觅i
旧时难觅i 2020-11-21 05:07

It\'s well known that comparing floats for equality is a little fiddly due to rounding and precision issues.

For example: https://randomascii.wordpress.com/2012/02/2

15条回答
  •  你的背包
    2020-11-21 06:01

    This maybe is a bit ugly hack, but it works pretty well when you don't need more than the default float precision (about 11 decimals).

    The round_to function uses the format method from the built-in str class to round up the float to a string that represents the float with the number of decimals needed, and then applies the eval built-in function to the rounded float string to get back to the float numeric type.

    The is_close function just applies a simple conditional to the rounded up float.

    def round_to(float_num, prec):
        return eval("'{:." + str(int(prec)) + "f}'.format(" + str(float_num) + ")")
    
    def is_close(float_a, float_b, prec):
        if round_to(float_a, prec) == round_to(float_b, prec):
            return True
        return False
    
    >>>a = 10.0
    10.0
    >>>b = 10.0001
    10.0001
    >>>print is_close(a, b, prec=3)
    True
    >>>print is_close(a, b, prec=4)
    False
    

    Update:

    As suggested by @stepehjfox, a cleaner way to build a rount_to function avoiding "eval" is using nested formatting:

    def round_to(float_num, prec):
        return '{:.{precision}f}'.format(float_num, precision=prec)
    

    Following the same idea, the code can be even simpler using the great new f-strings (Python 3.6+):

    def round_to(float_num, prec):
        return f'{float_num:.{prec}f}'
    

    So, we could even wrap it up all in one simple and clean 'is_close' function:

    def is_close(a, b, prec):
        return f'{a:.{prec}f}' == f'{b:.{prec}f}'
    

提交回复
热议问题