Matlab precision: simple subtraction is not zero

前端 未结 5 1983
野趣味
野趣味 2021-01-16 13:20

I compute this simple sum on Matlab:

2*0.04-0.5*0.4^2 = -1.387778780781446e-017

but the result is not zero. What can I do?

相关标签:
5条回答
  • 2021-01-16 13:43

    Matlab uses double-precision floating-point numbers to store real numbers. These are numbers of the form m*2^e where m is an integer between 2^52 and 2^53 (the mantissa) and e is the exponent. Let's call a number a floating-point number if it is of this form.

    All numbers used in calculations must be floating-point numbers. Often, this can be done exactly, as with 2 and 0.5 in your expression. But for other numbers, most notably most numbers with digits after the decimal point, this is not possible, and an approximation has to be used. What happens in this case is that the number is rounded to the nearest floating-point number.

    So, whenever you write something like 0.04 in Matlab, you're really saying "Get me the floating-point number that is closest to 0.04. In your expression, there are 2 numbers that need to be approximated: 0.04 and 0.4.

    In addition, the exact result of operations like addition and multiplication on floating-point numbers may not be a floating-point number. Although it is always of the form m*2^e the mantissa may be too large. So you get an additional error from rounding the results of operations.

    At the end of the day, a simple expression like yours will be off by about 2^-52 times the size of the operands, or about 10^-17.

    In summary: the reason your expression does not evaluate to zero is two-fold:

    1. Some of the numbers you start out with are different (approximations) to the exact numbers you provided.
    2. The intermediate results may also be approximations of the exact results.
    0 讨论(0)
  • 2021-01-16 13:43

    I do not know if it is applicable to your problem but often the simplest solution is to scale your data.

    For example:

    a=0.04;
    b=0.2;
    a-0.2*b
    ans=-6.9389e-018
    c=a/min(abs([a b]));
    d=b/min(abs([a b]));
    c-0.2*d
    ans=0
    

    EDIT: of course I did not mean to give a universal solution to these kind of problems but it is still a good practice that can make you avoid a few problems in numerical computation (curve fitting, etc ...). See Jim Clay's answer for the reason why you are experiencing these problems.

    0 讨论(0)
  • 2021-01-16 13:51

    What you are seeing is quantization error. Matlab uses doubles to represent numbers, and while they are capable of a lot of precision, they still cannot represent all real numbers because there are an infinite number of real numbers. I'm not sure about Aabaz's trick, but in general I would say there isn't anything you can do, other than perhaps massaging your inputs to be double-friendly numbers.

    0 讨论(0)
  • 2021-01-16 13:58

    Aabaz and Jim Clay have good explanations of what's going on.

    It's often the case that, rather than exactly calculating the value of 2*0.04 - 0.5*0.4^2, what you really want is to check whether 2*0.04 and 0.5*0.4^2 differ by an amount that is small enough to be within the relevant numerical precision. If that's the case, than rather than checking whether 2*0.04 - 0.5*0.4^2 == 0, you can check whether abs(2*0.04 - 0.5*0.4^2) < thresh. Here thresh can either be some arbitrary smallish number, or an expression involving eps, which gives the precision of the numerical type you're working with.

    EDIT: Thanks to Jim and Tal for suggested improvement. Altered to compare the absolute value of the difference to a threshold, rather than the difference.

    0 讨论(0)
  • 2021-01-16 14:00

    I'm pretty sure this is a case of ye olde floating point accuracy issues.

    Do you need 1e-17 accuracy? Is this merely a case of wanting 'pretty' output? In that case, you can just use a formatted sprintf to display the number of significant digits you want.

    Realize that this is not a matlab problem, but a fundamental limitation of how numbers are represented in binary.

    For fun, work out what .1 is in binary...

    Some references: http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems http://www.mathworks.com/support/tech-notes/1100/1108.html

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