为什么GNU科学图书馆文件trig.c中的PI分为三部分?

时间:2016-09-24 10:37:28

标签: math floating-point gnu gsl pi

在下面的代码中,为什么Pi分为三个常数P1,P2和P3?有一些相关的数学理论吗?如果它是为了提高r的计算精度,我运行代码的精度更高但没有任何改进而不仅仅是Pi。(来自gsl / specfunc / trig.c:576的代码)

  const double P1 = 4 * 7.85398125648498535156e-01;
  const double P2 = 4 * 3.77489470793079817668e-08;
  const double P3 = 4 * 2.69515142907905952645e-15;
  const double TwoPi = 2*(P1 + P2 + P3);

  const double y = 2*floor(theta/TwoPi);

  double r = ((theta - y*P1) - y*P2) - y*P3;

1 个答案:

答案 0 :(得分:4)

C中的测试程序

#include<math.h>
#include<stdio.h>


double mod2pi(double theta) {
  const double P1 = 4 * 7.85398125648498535156e-01;
  const double P2 = 4 * 3.77489470793079817668e-08;
  const double P3 = 4 * 2.69515142907905952645e-15;
  const double TwoPi = 2*(P1 + P2 + P3);

  const double y = 2*floor(theta/TwoPi);

  return ((theta - y*P1) - y*P2) - y*P3;
}

int main() {
  double x = 1.234e+7;

  printf("x=%.16e\nfmod  =%.16e\nmod2pi=%.16e\n",x,fmod(x,2*M_PI), mod2pi(x));

  return 0;
}

与使用Magma online calculator

的多精度结果进行比较
RR := RealField(100);
pi := Pi(RR);
x := 1.234e+7;
n := 2*Floor(x/(2*pi));
"magma =",RR!x-n*pi;

结果

x=1.2340000000000000e+07
fmod  =6.2690732008483607e+00
mod2pi=6.2690732003673268e+00

magma = 6.269073200367326567623794342882040802035079748091348034188201251009459335653510999632076033999854435

表明确实更高的努力会带来更精确的结果。

为什么这些常量

出于某种原因,开发人员决定不直接分割pi/4但基于10*pi/4=5/2*pi的位,如下表所示,其中顶行是{的长版本的位{1}}而接下来的三个是常量的二进制表示乘以5/2*pi

10

基于111 11011010100111101000101001010101010011100001011110010110000011111010111110 111.1101101010011110100001 0.00000000000000000000011001010101010011100001 0.000000000000000000000000000000000000000000000111100101100000 的拆分,每个部分使用25位

pi/4

并将导致常量

0.1100100100001111110110101010001000100001011010001100001000110100110001001100

0.1100100100001111110110101
0.00000000000000000000000000100010001000010110100011
0.000000000000000000000000000000000000000000000000000000100011010011000100110

这个想法是整数倍const double P1 = 4 * 7.85398155450820922852e-01; const double P2 = 4 * 7.94662735614792836714e-09; const double P3 = 4 * 3.06161646971842959369e-17; 的{​​{1}}是精确的,因此连续的减少会删除前导相同的位而不会丢失精度。本质上,53位尾数的输入参数通过填充零(实际上)扩展到75位尾数,然后这个数字精确地减少2^27的倍数。取消最多22个前导位不会导致精度损失。