- 注册时间
- 2007-12-28
- 最后登录
- 1970-1-1
- 威望
- 星
- 金币
- 枚
- 贡献
- 分
- 经验
- 点
- 鲜花
- 朵
- 魅力
- 点
- 上传
- 次
- 下载
- 次
- 积分
- 12785
- 在线时间
- 小时
|
发表于 2008-10-8 11:45:26
|
显示全部楼层
下面给出两个计算 double数自然对数的函数,精度可达到12位10进制数的版本。第一个函数是Ln_2,第二个函数是Ln_3( 实际上我写了三个函数,另外的一个是Ln_1,这个函数效率较低,没有给出)。对于任意双精度浮点数,Ln_3只需要做11次浮点乘除法,就可以达到12位以上的精度。
主要算法:
若$ 1- typedef unsigned short WORD;
- typedef unsigned long DWORD;
-
- #define LN2 0.69314718055994530941723212145818 //log(2)
- #define DIG_NUM 12 //精确到12位有效数字
- //#define DIG_NUM 15 //精确到15位有效数字
- static double pow2[]=
- {
- 1.3407807929942597e+154,
- 1.1579208923731620e+077,
- 3.4028236692093846e+038,
- 1.8446744073709552e+019,
- 4.2949672960000000e+009,
- 6.5536000000000000e+004,
- 2.5600000000000000e+002,
- 1.6000000000000000e+001,
- 4.0000000000000000,
- 2.0000000000000000,
- 1.4142135623730951,
- 1.1892071150027210,
- 1.0905077326652577,
- 1.0442737824274138,
- 1.0218971486541166,
- // 测试表明,当查表时查到 1.0218971486541166 这一项时,在其后
- // 阶段,当精度达到10^-12时,应用泰勒公式,只需要计算3项,
- // 即x, x^3/3, x^5/5,
- // 从而使得整个计算过程达到最优,至多只需要11次浮点乘除法,具体算法见
- // 函数Ln_3
-
-
- 1.0108892860517005,
- 1.0054299011128027,
- 1.0027112750502025,
- 1.0013547198921082,
- 1.0006771306930664
- };
-
- static double pow2_exp[]=
- {
- 5.1200000000000000e+002,
- 2.5600000000000000e+002,
- 1.2800000000000000e+002,
- 6.4000000000000000e+001,
- 3.2000000000000000e+001,
- 1.6000000000000000e+001,
- 8.0000000000000000e+000,
- 4.0000000000000000e+000,
- 2.0000000000000000e+000,
- 1.0000000000000000e+000,
- 5.0000000000000000e-001,
- 2.5000000000000000e-001,
- 1.2500000000000000e-001,
- 6.2500000000000000e-002,
- 3.1250000000000000e-002,
- 1.5625000000000000e-002,
- 7.8125000000000000e-003,
- 3.9062500000000000e-003,
- 1.9531250000000000e-003,
- 9.7656250000000000e-004
- };
-
- short GetExpBase2(double a) // 获得 a 的阶码
- {
- // 按照IEEE 754浮点数格式,取得阶码,仅仅适用于Intel 系列 cpu
- WORD *pWord=(WORD *)(&a)+3;
- WORD rank = ( (*pWord & 0x7fff) >>4 );
- return (short)(rank-0x3ff);
- }
-
- double GetMantissa(double a) // 获得 a 的 尾数
- {
- // 按照IEEE 754浮点数格式,取得尾数,仅仅适用于Intel 系列 cpu
- WORD *pWord=(WORD *)(&a)+3;
- *pWord &= 0x800f; //清除阶码
- *pWord |= 0x3ff0; //重置阶码
- return a;
- }
-
- // 对数计算公式:
- // 若x>1,y=(x-1)/(x+1),则有
- // log(x)=2*(y+ y^3/3 + y^5/5 + y^7/7 + y^9/9 + ... y^(2k+1)/2k)(k为非负整数)
-
- // 计算log(x)的第2个版本,
- // x>0
- double Ln_2(double x)
- {
- double r0,r1;
- double item;
- double s;
- int i;
- if (x<1)
- return -(Ln_2(1.0/x));
-
- for (r0=0,i=0;i<=9+5;i++)
- {
- if ( x>= pow2[i])
- {
- r0+= pow2_exp[i];
- x/= pow2[i];
- }
- }
- //此时x必然小于1.0218971486541
-
- r0 *= LN2;
- x=(x-1)/(x+1);
- // 此时x小于0.010830001253374,2*x^7/7小于4.99265e-015,因此计算泰勒公式的前3项足够
-
- s=x*x;
- r1=item=x; //计算泰勒公式第1项
- #if DIG_NUM ==12
- for (i=3;i<=5;i+=2) //精确到12位有效数字
- #else
- for (i=3;i<=7;i+=2) //精确到15位有效数字
- #endif
- {
- item *= s;
- r1 += item/i; //泰勒公式其他3项
- }
- return r0+r1*2;
- }
-
- // 计算log(x)的第3个版本,速度更快,
- // 精确到10^12,至多只需要11次浮点乘除法
- // 要求:x必须是 IEEE754标准浮点格式,字节顺序是intel格式,在某些CPU可能不能正确工作
- double Ln_3(double x)
- {
- double r0,r1;
- double item;
- double s;
- int i;
- if (x<1)
- return -(Ln_3(1.0/x));
-
- r0= GetExpBase2(x);
- x= GetMantissa(x);
-
- for (i=9+1;i<=9+5;i++)
- {
- if ( x>= pow2[i])
- {
- r0+= pow2_exp[i]; x/= pow2[i];
- }
- }
-
- r0 *= LN2;
- x=(x-1)/(x+1);
- s=x*x;
-
- r1=item=x; //计算泰勒公式第1项
- #if DIG_NUM ==12
- for (i=3;i<=5;i+=2) //精确到12位有效数字
- #else
- for (i=3;i<=7;i+=2) //精确到15位有效数字
- #endif
- {
- item *= s;
- r1 += item/i; //泰勒公式其他2项
- }
- return r0+r1*2;
- }
复制代码 |
|