找回密码
 欢迎注册
楼主: forfreeidea

[求助] 求助函数lnx 以及指数函数用汇编实现的算法

[复制链接]
发表于 2008-10-6 10:09:27 | 显示全部楼层
应该说,我对计算高精度对数函数值还是很有研究的,目前仍然在研究高精度对数的快速算法,目标是在中等精度(大约几百位到几万位)的情况下,作出一个世界上最快的对数计算器。
在csdn 也曾经遇到过类似的问题,我也做了一些回答,下面给出一些链接,不知对你是否有用。
如何在汇编里面编写求对数的子程序? 高分求助!(http://topic.csdn.net/t/20050908/10/4256707.html
如何写一个程序算出lg(i)的值?(http://topic.csdn.net/t/20050113/16/3723330.html
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-10-6 20:27:28 | 显示全部楼层
楼上的程序只能精确到2位有效数字,明天给出一个可精确到12为有效数字的版本。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-10-8 11:45:26 | 显示全部楼层
下面给出两个计算 double数自然对数的函数,精度可达到12位10进制数的版本。第一个函数是Ln_2,第二个函数是Ln_3( 实际上我写了三个函数,另外的一个是Ln_1,这个函数效率较低,没有给出)。对于任意双精度浮点数,Ln_3只需要做11次浮点乘除法,就可以达到12位以上的精度。
主要算法:
  若$ 1<x<2, 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+1))(k为非负整数)$
  1. typedef unsigned short WORD;
  2. typedef unsigned long DWORD;

  3. #define LN2 0.69314718055994530941723212145818 //log(2)
  4. #define DIG_NUM 12 //精确到12位有效数字
  5. //#define DIG_NUM 15 //精确到15位有效数字
  6. static double pow2[]=
  7. {
  8. 1.3407807929942597e+154,
  9. 1.1579208923731620e+077,
  10. 3.4028236692093846e+038,
  11. 1.8446744073709552e+019,
  12. 4.2949672960000000e+009,
  13. 6.5536000000000000e+004,
  14. 2.5600000000000000e+002,
  15. 1.6000000000000000e+001,
  16. 4.0000000000000000,
  17. 2.0000000000000000,
  18. 1.4142135623730951,
  19. 1.1892071150027210,
  20. 1.0905077326652577,
  21. 1.0442737824274138,
  22. 1.0218971486541166,
  23. // 测试表明,当查表时查到 1.0218971486541166 这一项时,在其后
  24. // 阶段,当精度达到10^-12时,应用泰勒公式,只需要计算3项,
  25. // 即x, x^3/3, x^5/5,
  26. // 从而使得整个计算过程达到最优,至多只需要11次浮点乘除法,具体算法见
  27. // 函数Ln_3


  28. 1.0108892860517005,
  29. 1.0054299011128027,
  30. 1.0027112750502025,
  31. 1.0013547198921082,
  32. 1.0006771306930664
  33. };

  34. static double pow2_exp[]=
  35. {
  36. 5.1200000000000000e+002,
  37. 2.5600000000000000e+002,
  38. 1.2800000000000000e+002,
  39. 6.4000000000000000e+001,
  40. 3.2000000000000000e+001,
  41. 1.6000000000000000e+001,
  42. 8.0000000000000000e+000,
  43. 4.0000000000000000e+000,
  44. 2.0000000000000000e+000,
  45. 1.0000000000000000e+000,
  46. 5.0000000000000000e-001,
  47. 2.5000000000000000e-001,
  48. 1.2500000000000000e-001,
  49. 6.2500000000000000e-002,
  50. 3.1250000000000000e-002,
  51. 1.5625000000000000e-002,
  52. 7.8125000000000000e-003,
  53. 3.9062500000000000e-003,
  54. 1.9531250000000000e-003,
  55. 9.7656250000000000e-004
  56. };

  57. short GetExpBase2(double a) // 获得 a 的阶码
  58. {
  59.     // 按照IEEE 754浮点数格式,取得阶码,仅仅适用于Intel 系列 cpu
  60.     WORD *pWord=(WORD *)(&a)+3;
  61.     WORD rank = ( (*pWord & 0x7fff) >>4 );
  62.     return (short)(rank-0x3ff);
  63. }

  64. double GetMantissa(double a) // 获得 a 的 尾数
  65. {
  66.     // 按照IEEE 754浮点数格式,取得尾数,仅仅适用于Intel 系列 cpu
  67.     WORD *pWord=(WORD *)(&a)+3;
  68.     *pWord &= 0x800f;  //清除阶码
  69.     *pWord |= 0x3ff0;  //重置阶码
  70.     return a;
  71. }

  72. // 对数计算公式:
  73. //  若x>1,y=(x-1)/(x+1),则有
  74. //  log(x)=2*(y+ y^3/3 + y^5/5 + y^7/7 + y^9/9 + ... y^(2k+1)/2k)(k为非负整数)

  75. // 计算log(x)的第2个版本,
  76. // x>0
  77. double Ln_2(double x)
  78. {
  79. double r0,r1;
  80. double item;
  81. double s;
  82. int i;
  83. if (x<1)
  84. return -(Ln_2(1.0/x));

  85. for (r0=0,i=0;i<=9+5;i++)
  86. {
  87. if ( x>= pow2[i])
  88. {
  89. r0+= pow2_exp[i];
  90. x/= pow2[i];
  91. }
  92. }
  93. //此时x必然小于1.0218971486541

  94. r0 *= LN2;
  95. x=(x-1)/(x+1);
  96. // 此时x小于0.010830001253374,2*x^7/7小于4.99265e-015,因此计算泰勒公式的前3项足够

  97. s=x*x;
  98. r1=item=x; //计算泰勒公式第1项
  99. #if DIG_NUM ==12
  100. for (i=3;i<=5;i+=2)  //精确到12位有效数字
  101. #else
  102. for (i=3;i<=7;i+=2)  //精确到15位有效数字
  103. #endif
  104. {
  105. item *= s;
  106. r1 += item/i;  //泰勒公式其他3项
  107. }
  108. return r0+r1*2;
  109. }

  110. // 计算log(x)的第3个版本,速度更快,
  111. // 精确到10^12,至多只需要11次浮点乘除法
  112. // 要求:x必须是 IEEE754标准浮点格式,字节顺序是intel格式,在某些CPU可能不能正确工作
  113. double Ln_3(double x)
  114. {
  115. double r0,r1;
  116. double item;
  117. double s;
  118. int i;
  119. if (x<1)
  120. return -(Ln_3(1.0/x));

  121. r0= GetExpBase2(x);
  122. x= GetMantissa(x);

  123. for (i=9+1;i<=9+5;i++)
  124. {
  125. if ( x>= pow2[i])
  126. {
  127. r0+= pow2_exp[i]; x/= pow2[i];
  128. }
  129. }

  130. r0 *= LN2;
  131. x=(x-1)/(x+1);
  132. s=x*x;

  133. r1=item=x; //计算泰勒公式第1项
  134. #if DIG_NUM ==12
  135. for (i=3;i<=5;i+=2)  //精确到12位有效数字
  136. #else
  137. for (i=3;i<=7;i+=2)  //精确到15位有效数字
  138. #endif
  139. {
  140. item *= s;
  141. r1 += item/i;  //泰勒公式其他2项
  142. }
  143. return r0+r1*2;
  144. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-10-8 11:47:27 | 显示全部楼层


他需要的是51系列的代码
可能不能用某些技巧的
因为硬件并不支持浮点操作
且是8位CPU
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-10-8 11:54:31 | 显示全部楼层
我是知道这一点,所以给出2个版本的算法。
我不可能知道每一种CPU的汇编,只能给出算法和C语言代码。具体到某一种CPU,当然需要他自己用汇编语言去实现这个算法了,其中包括实现 类似C语言浮点数的 表示方法和运算方法。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-10-8 11:58:07 | 显示全部楼层
呵呵
C51不知道具体如何运算的
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-10-8 12:19:07 | 显示全部楼层
下面给出计算指数函数的简单算法

a,b为任意浮点数,求$a^x$.

step1:  将x表示为2进制,整数部分存入数组 $a_i, 0<=i<=k$,小数部分存入数组$b_i,1<=i<=m$,如13.75可表示为 1101.11, 数组a[0..3]={1,0,1,1},数组b[1..2]={1,1}
step2:  计算$a^(2^0),a^(2^1),a^(2^2),直到a^(2^k)$, 存入数组$e1_i,0<=i<=k$, 对于13.75,需要计算到$a^8$.
step3:  计算$a^(2^-1),a^(2^-2),b^(2^-3)$, 直到$b^(2^-m)$,存入数组$e2_i,1<=i<=m$, 对于13.75,需要计算到$a^(1/4)$
step4:  $r=1$
step5:  如 $a_i>0,0<=i<=k$,则计算$r =  r ** e1_i$
step6:  如 $b_i>0,1<=i<=m$,则计算$r = r ** e2_i$
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-10-8 12:25:49 | 显示全部楼层
楼上用到开平方算法,具体算法可在本站中查找。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-10-8 12:42:22 | 显示全部楼层
不错,学习了!
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

小黑屋|手机版|数学研发网 ( 苏ICP备07505100号 )

GMT+8, 2024-5-3 13:13 , Processed in 0.044033 second(s), 14 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表