使用变精度算术

时间:2018-04-04 11:11:10

标签: matlab octave symbolic-math arbitrary-precision

假设您想要使用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所需的小数位数增加到81vpa会在Matlab中给出相同的答案,因为舍入和进位会使最后的数字为零, Matlab修剪尾随零。
  • Octave没有修剪,所以它显示那些零,但它们仍然不正确。

因此,在Matlab和Octave中,正确获取第一个79有效数字要求在这种情况下至少要求三个额外数字

以上例子说明了

  • 由于四舍五入,vpa的最后一位数字可能会被关闭;
  • 要求一个额外的数字并不足够;
  • 避免舍入问题所需的额外数字的数量可以任意大。如果在想要的数字之后有很长一段时间,就会发生这种情况。

那么,有没有办法获得数字的第一个W有效数字,并保证它们是正确的,即不受舍入问题的影响?

2 个答案:

答案 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}}否则。该图说明了这一点。

enter image description here

根据问题中的观察,有四种可能的情况。在以下示例中,有用数字的数量为A = 0,并使用了Matlab。

  1. W = 3N = 0:无需额外数字。

    A = 0
  2. >> disp(vpa(sym('0.12345'),3)) % works: first 3 digits are correct 0.123 N = 0:正确获取第一个A = 1数字需要一个额外的数字:

    W = 3
  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 > 0A = 0需要额外的数字:

    N
  4. >> 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 > 0A = 1需要额外的数字:

    N+1
  5. >> 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 + AN都是未知。因此,一种可能的方法是尝试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位数的精度。这基本上就是为什么我们有保护数字,他们增加精度“没有”告诉我们。