Function to determine if two numbers are nearly equal when rounded to n significant decimal digits

前端 未结 11 1855

I have been asked to test a library provided by a 3rd party. The library is known to be accurate to n significant figures. Any less-significant errors can safely be

相关标签:
11条回答
  • 2020-12-03 02:48

    This is a fairly common issue with floating point numbers. I solve it based on the discussion in Section 1.5 of Demmel[1]. (1) Calculate the roundoff error. (2) Check that the roundoff error is less than some epsilon. I haven't used python in some time and only have version 2.4.3, but I'll try to get this correct.

    Step 1. Roundoff error

    def roundoff_error(exact, approximate):
        return abs(approximate/exact - 1.0)
    

    Step 2. Floating point equality

    def float_equal(float1, float2, epsilon=2.0e-9):
        return (roundoff_error(float1, float2) < epsilon)
    

    There are a couple obvious deficiencies with this code.

    1. Division by zero error if the exact value is Zero.
    2. Does not verify that the arguments are floating point values.

    Revision 1.

    def roundoff_error(exact, approximate):
        if (exact == 0.0 or approximate == 0.0):
            return abs(exact + approximate)
        else:
            return abs(approximate/exact - 1.0)
    
    def float_equal(float1, float2, epsilon=2.0e-9):
        if not isinstance(float1,float):
            raise TypeError,"First argument is not a float."
        elif not isinstance(float2,float):
            raise TypeError,"Second argument is not a float."
        else:
            return (roundoff_error(float1, float2) < epsilon)
    

    That's a little better. If either the exact or the approximate value is zero, than the error is equal to the value of the other. If something besides a floating point value is provided, a TypeError is raised.

    At this point, the only difficult thing is setting the correct value for epsilon. I noticed in the documentation for version 2.6.1 that there is an epsilon attribute in sys.float_info, so I would use twice that value as the default epsilon. But the correct value depends on both your application and your algorithm.

    [1] James W. Demmel, Applied Numerical Linear Algebra, SIAM, 1997.

    0 讨论(0)
  • 2020-12-03 02:48

    Oren Shemesh got part of the problem with the problem as stated but there's more:

    assert nearlyequal( 0.0, 1e-15, 5 )

    also fails the second definition (and that's the definition I learned in school.)

    No matter how many digits you are looking at, 0 will not equal a not-zero. This could prove to be a headache for such tests if you have a case whose correct answer is zero.

    0 讨论(0)
  • 2020-12-03 02:51

    There are already plenty of great answers, but here's a think:

    def closeness(a, b):
      """Returns measure of equality (for two floats), in unit
         of decimal significant figures."""
      if a == b:
        return float("infinity")
      difference = abs(a - b)
      avg = (a + b)/2
      return math.log10( avg / difference )
    
    
    if closeness(1000, 1000.1) > 3:
      print "Joy!"
    
    0 讨论(0)
  • 2020-12-03 02:52

    I have been asked to test a library provided by a 3rd party

    If you are using the default Python unittest framework, you can use assertAlmostEqual

    self.assertAlmostEqual(a, b, places=5)
    
    0 讨论(0)
  • 2020-12-03 02:57

    As of Python 3.5, the standard way to do this (using the standard library) is with the math.isclose function.

    It has the following signature:

    isclose(a, b, rel_tol=1e-9, abs_tol=0.0)
    

    An example of usage with absolute error tolerance:

    from math import isclose
    a = 1.0
    b = 1.00000001
    assert isclose(a, b, abs_tol=1e-8)
    

    If you want it with precision of n significant digits, simply replace the last line with:

    assert isclose(a, b, abs_tol=10**-n)
    
    0 讨论(0)
  • 2020-12-03 03:00

    There are lots of ways of comparing two numbers to see if they agree to N significant digits. Roughly speaking you just want to make sure that their difference is less than 10^-N times the largest of the two numbers being compared. That's easy enough.

    But, what if one of the numbers is zero? The whole concept of relative-differences or significant-digits falls down when comparing against zero. To handle that case you need to have an absolute-difference as well, which should be specified differently from the relative-difference.

    I discuss the problems of comparing floating-point numbers -- including a specific case of handling zero -- in this blog post:

    http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/

    0 讨论(0)
提交回复
热议问题