提问人:Steven Ding 提问时间:7/12/2022 最后编辑:Steven Ding 更新时间:7/14/2022 访问量:65
生成数值序列时的 MATLAB 数值精度
MATLAB numeric precision when generating a numeric sequence
问:
我正在测试这样的操作:
[input] 3.9/0.1 : 4.1/0.1
[output] 39 40
不知道为什么近似为 .如果我添加一个 ,它将按预期进行:4.1/0.1
40
round()
[input] 3.9/0.1 : round(4.1/0.1)
[output] 39 40 41
第一次手术有什么问题?
答:
浮点数在用固定位数(MATLAB 中默认为 64 位)表示时会损失精度。这是因为有无限数量的实数(即使在 0.0 到 0.1 的小范围内)。另一方面,n 位二进制模式可以表示有限的 2^n 个不同数。因此,并非所有实数都可以表示。将改用最接近的近似值,从而导致准确性损失。
在计算机中,作为 64 位双精度浮点数的最接近的可表示值实际上是,4.1/0.1
4.1/0.1 ≈ 40.9999999999999941713291207...
所以,从本质上讲,这就是你从这个系列中得到的。例如,如果减去 .但是,当您四舍五入时,您会得到最接近预期的值。4.1/0.1 < 41.0
41 - 4.1/0.1 = 7.105427357601002e-15
41.0
根据 IEEE-754 标准的 64 位双精度表示方案:
- 最高有效位是符号位 (S),0 表示正数,1 表示负数。
- 以下 11 位表示指数 (E)。
- 剩下的 52 位代表分数 (F)。
在本次问答中,我将详细介绍冒号运算符如何在MATLAB中工作以创建范围。但是,此处未涵盖导致此问题中描述的问题的详细信息。
该帖子包含一个函数的完整代码,该函数完全模仿冒号运算符的功能。让我们按照该代码进行操作。我们从 开始,它正好是 39,并且 ,由于舍入误差,它仅略小于 41,并且(如果未给出,则为默认值)。start = 3.9/0.1
stop = 4.1/0.1
step = 1
它首先计算公差:
tol = 2.0*eps*max(abs(start),abs(stop));
此容差旨在用于在最后一个步骤超过该值时,如果该值在确切的步长数范围内,则仍会使用该值。如果没有容差,就很难使用浮点终点和步长来构建正确的序列。stop
tol
但是,然后我们得到这个测试:
if start == floor(start) && step == 1
% Consecutive integers.
n = floor(stop) - start;
elseif ...
如果起始值是精确整数,并且步长为 1,则它会强制序列为整数序列。不幸的是,它是通过将步数作为 和 之间的距离来实现的。也就是说,在确定正确的止损点时,它没有使用之前计算的公差!如果略高于整数,则该整数将在范围内。如果略低于整数(如 OP 的情况),则该整数将不属于范围。floor(stop)
start
stop
stop
在这种情况下,MATLAB是否应该将数字四舍五入可能会有争议。 MATLAB选择不这样做。冒号运算符生成的所有序列都使用与用户给出的完全相同的 and 值。它留给用户来确保序列的边界符合要求。stop
start
stop
但是,如果冒号运算符没有对整数序列进行特殊处理,那么在这种情况下,结果就不会那么令人惊讶了。让我们在起始值中添加一个非常小的数字,因此它不是一个整数:
>> a = 3.9/0.1 : 4.1/0.1
a =
39 40
>> b = 3.9/0.1 + eps(39) : 4.1/0.1
b =
39.0000 40.0000 41.0000
上一个:对称带矩阵向量乘法
下一个:反正切函数的数值计算
评论