【问题标题】:Matlab array arithmetic inaccuracyMatlab数组算术不准确
【发布时间】:2012-06-09 19:13:41
【问题描述】:

当我试图在 matlab 中模拟我的正弦近似时,我发现了一个奇怪的问题。问题是当我将函数应用于数组时,它会返回一个结果,而将函数应用于单个值会给出稍微不同的结果。

在这个例子中我能够得到相同的行为:

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

我还发现了一些东西。一个是第一个结果是正确的(不是后者)。其次,重新排列sometimes可以解决问题。所以我不知道如何摆脱它。

【问题讨论】:

  • 所有浮点运算都有些不准确。

标签: arrays matlab floating-point precision floating-accuracy


【解决方案1】:

单精度最多只有 7 位十进制数字表示有意义的精度,所以说8.6909407e-001 是“正确的”而8.6909401e-001 是“错误的”在这种情况下意义不大。

正如您已经发现的,浮点运算对运算顺序也很敏感。当对矩阵而不是标量进行运算时,Matlab 可能会巧妙地改变计算顺序。

【讨论】:

  • 事实是我想用单精度数字获得零误差近似值。而且我可能已经这样做了,但是由于 Matlab,我不能相信这一点。那么有什么方法可以控制这种“自动”的计算顺序变化吗?
  • 没有。你无法控制它。
【解决方案2】:

对于向量算术,MatLab的线性代数库可能使用SIMD指令代替x87 FPU,精度会略有不同。

相对误差非常小,不应破坏任何合理设计的计算。您是否在测试浮点相等性?

【讨论】:

  • 不。我只想分析我的近似值的绝对和相对误差。由于这个嗯......异常我观察到一点不准确,而实际上并非如此。这很不愉快。
【解决方案3】:

我可以保证,任何使用浮点数学的设备实际上不会为数学相等的表达式提供二进制相等的结果。在您的各种平台上尝试以下 MATLAB 的等效项:

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

结果:

1.000000000001000e+16
1.000000000000000e+16

加法是可交换的,所以表达式在数学上是等价的。但是顺序在浮点世界中很重要。显然,当累加值在 0 左右时,按顺序添加 10000 个 1 对于浮点应该没有问题。但是一旦浮点“浮动”到 1e16,1 太小而无法表示,所以它永远不会已添加。

这里有一个额外的问题:x87 FPU 在内部以扩展精度(80 位)计算。因此,如果编译器决定将中间结果保存在 FPU 中,FPU 代码会给你一个不同的答案。相反,如果它决定将中间结果溢出到堆栈,则返回 64。如果决定使用 SSE 指令进行计算,则返回 64。

其他答案中建议的这些各种 MATLAB 技巧可能会让您足够接近您的问题。但是,如果您真的想要对系统进行完美建模,您可能需要一个更可控的仿真框架。也许使用vpa,在每一步都转换为正确的位数。或者切换到 C 或 C++,特别注意优化器控制设置。

或根据输入缩放以数学方式计算错误的界限,并验证您的答案始终低于界限。

【讨论】:

    【解决方案4】:

    使用单精度数字,两个结果都“相等”(差异小于single 类型的相对精度)。以下语句的计算结果为真:

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

    编辑

    如果您真的想对此进行控制,可以尝试禁用 MATLAB 加速器以强制它对常规代码和矢量化代码使用相同的执行路径:

    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) ))
    

    分别为第一/第二的结果:

    ans =
         0
    ans =
       5.9605e-08
    

    显然,默认情况下,加速器和即时编译器都处于打开状态。

    【讨论】:

    • 嗯...是的,你在写。但我认为在这种情况下,两个数字的二进制表示是相等的,但事实并非如此。
    • 它有效,但并非总是如此。不管怎样,谢谢。解决方案越多越好
    • @Menzoda:仅供参考,您能否分享一个不起作用的示例
    • 嘿。我记得我玩过数字,但加速功能出了点问题。但现在我无法获得相同的行为。
    • 在这一切中,我意识到浮点是一个非常微妙的问题。如果我们专门谈论我的问题,您的解决方案可能是最好的。
    【解决方案5】:

    好的。所有的答案都是正确的,但它们并不能解决问题。我想要的是数学上相等的表达式带来二进制相等的结果,无论我使用标量还是矢量算术。结果是我的 Cortex-M4、计算器和许多其他程序和设备中的 FPU,但不是 Matlab。

    到目前为止,我看到的唯一解决方案是使用for-loops 而不是向量算术。丑陋,但它有效。

    编辑

    感谢大家的回复,我们对此问题有了更多解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-27
      • 2014-01-19
      • 2012-04-14
      • 1970-01-01
      • 1970-01-01
      • 2020-06-06
      相关资源
      最近更新 更多