Matlab array arithmetic inaccuracy

人走茶凉 提交于 2020-01-15 12:12:21

问题


When i am trying to simulate my sine approximation in matlab i found a strange problem. The problem is that when i apply my function to an array, it returns one results, whereas applying functions to individual values ​​gives a slightly different result.

I was able to get same behaviour in this example:

z = single(0:0.001:1);
F = @(x) (x.^2 - single(1.2342320e-001)).*x.^2;  %some test function

z(999)        % Returns 9.9800003e-001
F(z(999))     % Returns 8.6909407e-001
temp = F(z);  
temp(999)     % Voila! It returns 8.6909401e-001

Also I found a few things. One is that first result is right (not the latter). Second, is that rearrangement of terms sometimes solves the problem. So i have no idea how to get rid of that.


回答1:


Using single-precision numbers, both results are "equal" (difference is smaller than the relative accuracy of the single type). The following statement evaluates to true:

max(abs( arrayfun(F,z) - F(z) )) < eps('single')

EDIT

If you really want to have control over this, you can try disabling the MATLAB accelerator to force it to use the same execution paths for both regular and vectorized code:

feature('jit', 'off')
feature('accel', 'off')
max(abs( arrayfun(F,z) - F(z) ))

feature('jit', 'on')
feature('accel', 'on')
max(abs( arrayfun(F,z) - F(z) ))

The result for the first/second respectively:

ans =
     0
ans =
   5.9605e-08

Obviously, by default both the accelerator and the just-in-time compiler are turned on.




回答2:


Single-precision only has up to 7 decimal digits of meaningful precision, so to say that 8.6909407e-001 is "right" and 8.6909401e-001 is "wrong" is not terribly meaningful in this situtaion.

Floating-point arithmetic is also sensitive to the order of operations, as you've already found. It's likely that Matlab subtly changes the order of calculations when operating on a matrix rather than a scalar.




回答3:


For vector arithmetic, MatLab's linear algebra library may use SIMD instructions instead of x87 FPU, and the precision will be slightly different.

The relative error is very very small, and shouldn't break any reasonably designed calculation. Are you testing for floating-point equality?




回答4:


I can guarantee that any device that uses floating point math will not, in fact, deliver binary-equal results for math-equal expressions. Try the equivalent of the following MATLAB on your various platforms:

a = [repmat(1, 10000, 1); 1e16];
format long
sum(a)
sum(flipud(a))

Results:

1.000000000001000e+16
1.000000000000000e+16

Addition is commutative, so the expressions are mathematically equivalent. But the order matters in floating-point world. Obviously, adding 10000 1's in sequence should present no problem for a floating-point, when the accumulation value is around 0. But once the floating-point has "floated" to 1e16, 1 is simply too small to be represented, so it's never added.

Here's an extra wrinkle: The x87 FPU computes in extended precision (80 bits), internally. So FPU code will give you a different answer, if the compiler decides to keep the intermediate results inside the FPU. If instead it decides to spill intermediate results to the stack, then you're back to 64. If it decides to compute using the SSE instructions, then you're back to 64.

These various MATLAB tricks suggested in the other answers might get you close enough for your problem. But if you're really after perfect modelling of your system, you'll probably need a simulation framework that is more controllable. Perhaps using vpa, with conversion to the correct number of bits at each step. Or switch to C or C++, paying extremely careful attention to the optimizer control settings.

Or mathematically compute the bounds on your error based on the input scaling, and verify that your answer is always below the bound.




回答5:


Okay. All answers are right, but they doesn't solve the problem. All I want is that mathematically-equal expressions brings binary-equal result, regardless of if I use scalar or vector arithmetic. The result that brings me FPU in my Cortex-M4, my calculator, and many other programms and devices, but not Matlab.

So far, the only solution that I see is to use for-loops instead of vector arithmetic. Ugly, but it works.

EDIT

Thanks to the responses we have some more solutions for this problem.



来源:https://stackoverflow.com/questions/10963823/matlab-array-arithmetic-inaccuracy

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!