假设您想要使用vpa
知道数字的第一个W
有效数字,例如pi。只需使用多个数字调用vpa
就无效。请考虑使用W = 35
的以下示例:
>> disp(vpa(sym('pi'), 35))
3.1415926535897932384626433832795029
这不起作用的原因是四舍五入。具体来说,上面的结果似乎表明pi的35
- 有效数字是9,实际上它是8的一部分:
>> disp(vpa(sym('pi'), 36))
3.14159265358979323846264338327950288
从上面看,似乎一个解决方案是要求一个额外的十进制并将其丢弃,以便最后存活的小数不会有舍入问题。但这通常也不会 ,因为舍入会导致进位。在Matlab中看到这个例子:
>> disp(vpa(sym('pi'), 79))
3.141592653589793238462643383279502884197169399375105820974944592307816406286209
>> disp(vpa(sym('pi'), 80))
3.141592653589793238462643383279502884197169399375105820974944592307816406286209
>> disp(vpa(sym('pi'), 81))
3.141592653589793238462643383279502884197169399375105820974944592307816406286209
>> disp(vpa(sym('pi'), 82))
3.141592653589793238462643383279502884197169399375105820974944592307816406286208999
>> disp(vpa(sym('pi'), 83))
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986
或Octave:
>> disp(vpa(sym('pi'), 79))
3.141592653589793238462643383279502884197169399375105820974944592307816406286209
>> disp(vpa(sym('pi'), 80))
3.1415926535897932384626433832795028841971693993751058209749445923078164062862090
>> disp(vpa(sym('pi'), 81))
3.14159265358979323846264338327950288419716939937510582097494459230781640628620900
>> disp(vpa(sym('pi'), 82))
3.141592653589793238462643383279502884197169399375105820974944592307816406286208999
>> disp(vpa(sym('pi'), 83))
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986
可以看出,
79
中将80
所需的小数位数增加到81
或vpa
会在Matlab中给出相同的答案,因为舍入和进位会使最后的数字为零, Matlab修剪尾随零。因此,在Matlab和Octave中,正确获取第一个79
有效数字要求在这种情况下至少要求三个额外数字。
以上例子说明了
vpa
的最后一位数字可能会被关闭; 那么,有没有办法获得数字的第一个W
有效数字,并保证它们是正确的,即不受舍入问题的影响?
答案 0 :(得分:5)
首先,似乎无法预测vpa
何时将离开或朝零。以下结果与"圆的一半远离零","圆的一半到偶数"或任何usual rules:
>> disp(vpa(sym('0.135'),2))
0.14
>> disp(vpa(sym('0.125'),2))
0.12
>> disp(vpa(sym('0.115'),2))
0.11
Octave的结果也不一致,与Matlab不同:
>> disp(vpa(sym('0.135'),2))
0.14
>> disp(vpa(sym('0.125'),2))
0.13
>> disp(vpa(sym('0.115'),2))
0.11
这种不可预测性并没有真正影响答案,但它强制用更通用的术语表达,而不假设任何特定的舍入规则。
让W
成为想要的位数。超出该数字的所有数字将被称为不需要的。令N
为不需要的部分中的(可能为零)初始9的数量,如果不是9的第一个不需要的数字导致前一个数字从零开始舍入,则A = 1
,{ {1}}否则。该图说明了这一点。
根据问题中的观察,有四种可能的情况。在以下示例中,有用数字的数量为A = 0
,并使用了Matlab。
W = 3
,N = 0
:无需额外数字。
A = 0
>> disp(vpa(sym('0.12345'),3)) % works: first 3 digits are correct
0.123
,N = 0
:正确获取第一个A = 1
数字需要一个额外的数字:
W = 3
>> disp(vpa(sym('0.12378'),3)) % doesn't work
0.124
>> disp(vpa(sym('0.12378'),4)) % works: first 3 digits are correct
0.1238
,N > 0
:A = 0
需要额外的数字:
N
>> disp(vpa(sym('0.123994'),3)) % doesn't work
0.124
>> disp(vpa(sym('0.123994'),4)) % doesn't work
0.124
>> disp(vpa(sym('0.123994'),5)) % works: first 3 digits are correct
0.12399
,N > 0
:A = 1
需要额外的数字:
N+1
让>> disp(vpa(sym('0.123997'),3)) % doesn't work
0.124
>> disp(vpa(sym('0.123997'),4)) % doesn't work
0.124
>> disp(vpa(sym('0.123997'),5)) % doesn't work
0.124
>> disp(vpa(sym('0.123997'),6)) % works: first 3 digits are correct
0.123997
表示需要从E
询问的额外数字量,以确保第一个vpa
数字正确无误。然后,上述四种情况可以通过规则W
进行汇总。
在实践中,E = N + A
和N
都是未知。因此,一种可能的方法是尝试A
并继续增加E = 1
,直到最后获得的数字不是(可能已修剪)E
。然后,丢弃最后0
个数字会得到所需的结果。这种方法使用E
;也就是说,额外数字的数量是最小可能的,除了在没有实际需要额外数字时使用一个额外数字(上面的情况1)。
下面的代码为实数或虚数实现了这个,输出可能使用科学记数法。不支持复数(从输出字符串中更难找到位数)。
E = max(1, N+A)
答案 1 :(得分:4)
问题出现是因为Matlab使用guard digits来提高精度,如Matlab所述:
使用vpa函数指定的位数或 数字函数是保证的位数。在内部, 工具箱可以使用比您指定的更多的数字。这些额外的 数字称为保护数字。
要解决这个问题,我们必须关闭保护数字。 (联合国)幸运的是,Matlab不允许用户指定保护数字的数量,这是内部“计算”的内容。但是,John D'Errico写了一个High precision floating point arithmetic class (HPF),您可以在其中指定保护数字的数量。
DefaultNumberOfDigits 100 0
DefaultDecimalBase 1
将默认的位数设置为100,保护数字为0,并将迁移存储在1的“元组”中。如果我们现在回到Pi示例,我们得到
pie = hpf('pi',79)
pie = 3.141592653589793238462643383279502884197169399375105820974944592307816406286208
pie = hpf('pi',80)
pie = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089
pie = hpf('pi',81)
pie = 3.14159265358979323846264338327950288419716939937510582097494459230781640628620899
pie = hpf('pi',82)
pie = 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998
注意:这是解决舍入问题的解决方案。当您开始使用数字进行计算时,仍然存在标准问题。例如。如果数字5
的数字精度为100
,则不会为sqrt(5)
提供100
位数的精度。这基本上就是为什么我们有保护数字,他们增加精度“没有”告诉我们。