gpt4 book ai didi

MATLAB 使用 vpa() 时 mod() 的奇怪行为

转载 作者:行者123 更新时间:2023-12-03 23:45:55 25 4
gpt4 key购买 nike

如果我们有以下代码:

base = vpa(1); 
height = vpa(2.2);
mod(2*base + height + height, 2 * (base + height))
这将产生 6.4 的输出。我希望结果为 0,数值解确实给出 0。但我需要使用符号值 vpa() .
我做了一些实验来找出原因并发现:
simplify(2*base + height + height < 6.4)
simplify(2 * (base + height) == 6.4)
都给 TRUE .所以相同的(数字)表达式更小,等于 6.4。
我应该怎么做才能解决这个问题并得到 0 的答案?是什么导致了这个问题?

最佳答案

问题是vpa提供任意大的精度,但 不准确 .首先,请注意 vpa 第二个输入使用 digits 精度位数,即 32默认情况下。当你做

height = vpa(2.2)
这与
height = vpa(2.2, 32)
假设 digits32 .所以 height将有 32精度的数字,但不会精确。要看到这一点,请评估定义的 height更精确:
>> vpa(height, 32)
ans =
2.2
>> vpa(height, 40)
ans =
2.2
>> vpa(height, 50)
ans =
2.2000000000000000000000000000000000000001469367939
这种不准确导致了 2*base + height + height 之间的数值差异。和 2 * (base + height) ,这两者实际上都不等于 6.4 :
>> base = vpa(1); 
>> height = vpa(2.2);
>> vpa(2*base + height + height, 50)
ans =
6.3999999999999999999999999999999999999988245056492
>> vpa(2 * (base + height), 50)
ans =
6.4000000000000000000000000000000000000002938735877
结果,即使 mod(2*base + height + height, 2 * (base + height))好像是 0
>> mod(2*base + height + height, 2 * (base + height))
ans =
6.4

but it's _not_:

>> vpa(mod(2*base + height + height, 2 * (base + height)), 50)
ans =
6.3999999999999999999999999999999999999988245056492
注意与 6.4的偏差后一个结果不等于上述两个小偏差的总和;相反,它等于第一个。不保证数值不准确是可加性的。
总之, vpa减少但不能完全避免数值精度误差 .

如果我们增加用于 vpa 的位数会怎样? ?这会提供更高的精度并可能解决问题吗?
>> base = vpa(1, 1000); 
>> height = vpa(2.2, 1000);
奇怪的是,尽管使用了更多的数字,我们还是得到了和以前一样的不准确:
>> vpa(2*base + height + height, 50)
ans =
6.3999999999999999999999999999999999999988245056492
>> vpa(2 * (base + height), 50)
ans =
6.4000000000000000000000000000000000000002938735877
>> vpa(mod(2*base + height + height, 2 * (base + height)), 50)
ans =
6.3999999999999999999999999999999999999988245056492

因此,避免精度错误的唯一方法是替换 vpa来自 符号变量 , 分别是 精确 :
>> base = sym(1)
base =
1
>> height = sym(2.2)
height =
11/5
关于如何定义符号变量的题外话是有序的。请注意 sym(2.2)有它首先定义的潜在问题 2.2作为 double浮点数,其固有的不准确性,然后将其转换为 sym .在这种情况下,这不是问题,因为 2.2 的浮点数值表示恰好是准确的。事实上,我们可以检查 Matlab 是否显示 height = sym(2.2) ,这是准确的。此外,即使 double表示不准确,Matlab 会尝试猜测您的意图,并且通常会成功:
>> sym(3.141592653589793)
ans =
pi
(Matlab 假设我们指的是数字 pi)...但并非总是如此:
>> sym(sqrt(777))
ans =
777^(1/2)
>> sym(sqrt(777777))
ans =
7757421003204227/8796093022208
( sqrt(777) 给出 double 结果 27.874719729532707 ,它被 sym 识别为 777 的平方根的近似值。另一方面, sqrt(777777) 给出了 |114| 不识别的 7由 8.819166627295348e+02 作为 sym 的平方根的近似值)。
>> sym(7777)
ans =
7777
>> sym(7777777777777777777)
ans =
7777777777777777664
( 777777 完全表示为 7777 ,但 double 不是,因为它超过了 7777777777777777777 。)
所以,可以肯定的是, 保险箱 定义符号变量的方法是只使用 小整数 , 其他 符号变量 , 或 精确的字符串表示 :
>> height = sym('22/10')
height =
11/5
现在,与 2^53base正确定义为符号变量,我们得到预期的结果:
>> mod(2*base + height + height, 2 * (base + height))
ans =
0
>> vpa(mod(2*base + height + height, 2 * (base + height)), 1000)
ans =
0.0

关于MATLAB 使用 vpa() 时 mod() 的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62788258/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com