1

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?

Kara
  • 6,115
  • 16
  • 50
  • 57
Alejandro Ll.
  • 185
  • 4
  • 13
  • similar question: [Why is 24.0000 not equal to 24.0000 in MATLAB?](http://stackoverflow.com/questions/686439/why-is-24-0000-not-equal-to-24-0000-in-matlab) – Amro Oct 28 '11 at 03:19
  • also a much more obvious example: `0.3 - 0.1*3` which gives `5.5511e-017`. – Amro Oct 28 '11 at 03:21
  • 5.498+0.001 ans = 5.499000000000001 the correct answer should be 5.499 – opmfan Dec 09 '13 at 11:02

5 Answers5

4

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.

Sam Roberts
  • 23,951
  • 1
  • 40
  • 64
  • 2
    Good point. The one change I would make is that you need to compare the absolute value of the difference to "thresh". – Jim Clay Oct 27 '11 at 16:42
2

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.
Jeffrey Sax
  • 10,253
  • 3
  • 29
  • 40
1

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.

Aabaz
  • 3,106
  • 2
  • 21
  • 26
  • I honestly do not know but it certainly goes in the right direction to solve this kind of problems. – Aabaz Oct 27 '11 at 16:07
  • Is there a reason that this works, or is it just ad-hoc code that happens to do the "right" thing in this instance? – Oliver Charlesworth Oct 27 '11 at 17:50
  • This will not work always as can be seen by trying `f = @(x)1-x/x^2*x` and then `f(rand())` a few times. Sometimes it's 0; other times it's epsilon. Scaling helps you get better results, but the accuracy is still within epsilon. Another alternative is to scale epsilon to match the scale of the other values in the problem. – stardt Oct 29 '11 at 15:24
1

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.

Jim Clay
  • 963
  • 9
  • 24
1

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

hex4def6
  • 420
  • 3
  • 10