为什么使用在不同版本的 MATLAB(2016 与 2021)中运行的相同代码来计算sum(b.*x1)其中bis single 和x1is double 时会得到不同的结果。如何避免MATLAB版本之间出现此类错误?
MATLAB v.2021:
sum(b.*x1)
ans =
single
-0.0013286
Run Code Online (Sandbox Code Playgroud)
MATLAB 2016
sum(b.*x1)
ans =
single
-0.0013283
Run Code Online (Sandbox Code Playgroud)
sum在 R2017b 中,他们更改了单精度浮点数的行为,在 R2020b 中,他们也对其他数据类型进行了相同的更改。
这一变化加快了计算速度,并通过减少舍入误差提高了准确性。简而言之,以前的算法只是按顺序运行数组,将值相加。新行为计算数组较小部分的总和,然后将这些结果相加。这是更精确的,因为运行总计可能会变成一个非常大的数字,并且向其中添加较小的数字会导致这些较小的数字进行更多舍入。速度的提高来自循环展开:循环现在跨过,例如,当时的 8 个值,并且在循环体中,计算 8 个运行总计(它们不指定它们使用的数字,即 8这是一个例子)。
\n因此,新的结果比旧的结果更接近数组的总和。
\n有关更多详细信息(对新算法的更好解释以及更改原因),请参阅此博客文章。
\n关于如何避免差异:您可以实现自己的sum函数,并使用它而不是内置函数。为了提高效率,我建议将其编写为 MEX 文件。但是,请确保您匹配内置的较新行为sum,因为这是更好的近似值。
这是问题的一个例子。让我们创建一个包含N+1元素的数组,其中第一个元素的值为N,其余元素的值为 1。
N = 1e8;\na = ones(N+1,1,\'single\');\na(1) = N;\nRun Code Online (Sandbox Code Playgroud)\n该数组的总和预计为2*N。如果我们将N数据类型设置得足够大,我会在 R2017a 中看到这一点(更改之前):
>> sum(a)\nans =\n single\n 150331648\nRun Code Online (Sandbox Code Playgroud)\n我在 R2018b 中看到了这一点(在单精度更改之后sum):
>> sum(a)\nans =\n single\n 199998976\nRun Code Online (Sandbox Code Playgroud)\n两种实现都会出现舍入错误,但其中一种显然非常非常接近预期结果(2e8、 或200000000)。