PageRenderTime 64ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/cln-1.3.2/src/float/transcendental/cl_F_lnx.cc

#
C++ | 251 lines | 164 code | 13 blank | 74 comment | 31 complexity | 11fe2f6ee0eb006c847fcee58b706894 MD5 | raw file
Possible License(s): GPL-2.0
  1. // lnx().
  2. // General includes.
  3. #include "base/cl_sysdep.h"
  4. // Specification.
  5. #include "float/transcendental/cl_F_tran.h"
  6. // Implementation.
  7. #include "cln/float.h"
  8. #include "base/cl_low.h"
  9. #include "float/cl_F.h"
  10. #include "cln/lfloat.h"
  11. #include "float/lfloat/cl_LF.h"
  12. #include "cln/integer.h"
  13. #include "base/cl_inline.h"
  14. #include "float/lfloat/elem/cl_LF_zerop.cc"
  15. #include "float/lfloat/elem/cl_LF_minusp.cc"
  16. #include "float/lfloat/misc/cl_LF_exponent.cc"
  17. namespace cln {
  18. // cl_F lnx_naive (const cl_F& x)
  19. // cl_LF lnx_naive (const cl_LF& x)
  20. //
  21. // Methode:
  22. // y:=x-1, e := Exponent aus (decode-float y), d := (float-digits y)
  23. // Bei y=0.0 oder e<=-d liefere y
  24. // (denn bei e<=-d ist y/2 < 2^(-d)/2 = 2^(-d-1), also
  25. // 0 <= y - ln(x) < y^2/2 < 2^(-d-1)*y
  26. // also ist ln(x)/y, auf d Bits gerundet, gleich y).
  27. // Bei e<=-sqrt(d) verwende die Potenzreihe
  28. // ln(x) = sum(j=0..inf,(-1)^j*y^(j+1)/(j+1)):
  29. // a:=-y, b:=y, i:=1, sum:=0,
  30. // while (/= sum (setq sum (+ sum (/ b i)))) do i:=i+1, b:=b*a.
  31. // Ergebnis sum.
  32. // Sonst setze y := sqrt(x), berechne rekursiv z:=ln(y)
  33. // und liefere 2*z = (scale-float z 1).
  34. // Aufwand: asymptotisch d^0.5*M(d) = d^2.5 .
  35. const cl_LF lnx_naive (const cl_LF& x)
  36. {
  37. var cl_LF y = x-cl_float(1,x);
  38. if (zerop_inline(y)) // y=0.0 -> y als Ergebnis
  39. return y;
  40. var uintC actuallen = TheLfloat(x)->len;
  41. var uintC d = float_digits(x);
  42. var sintE e = float_exponent_inline(y);
  43. if (e <= -(sintC)d) // e <= -d ?
  44. return y; // ja -> y als Ergebnis
  45. { Mutable(cl_LF,x);
  46. var uintL k = 0; // Rekursionszähler k:=0
  47. // Bei e <= -1-limit_slope*floor(sqrt(d)) kann die Potenzreihe
  48. // angewandt werden.
  49. // Wähle für ln(1+y), naive1: limit_slope = 1.0,
  50. // für ln(1+y), naive2: limit_slope = 11/16 = 0.7,
  51. // für atanh(z), naive1: limit_slope = 0.6,
  52. // für atanh(z), naive1: limit_slope = 0.5.
  53. var sintL e_limit = -1-floor(isqrtC(d),2); // -1-floor(sqrt(d))
  54. while (e > e_limit) {
  55. // e > -1-floor(sqrt(d)) -> muß |y| verkleinern.
  56. x = sqrt(x); // x := (sqrt x)
  57. y = x-cl_float(1,x); // y := (- x 1) und
  58. e = float_exponent_inline(y); // e neu berechnen
  59. k = k+1; // k:=k+1
  60. }
  61. if (0) {
  62. // Potenzreihe ln(1+y) anwenden:
  63. var int i = 1;
  64. var cl_LF sum = cl_float(0,x); // sum := (float 0 x)
  65. var cl_LF a = -y;
  66. var cl_LF b = y;
  67. if (0) {
  68. // naive1:
  69. // floating-point representation
  70. loop {
  71. var cl_LF new_sum = sum + b/(cl_I)i; // (+ sum (/ b i))
  72. if (new_sum == sum) // = sum ?
  73. break; // ja -> Potenzreihe abbrechen
  74. sum = new_sum;
  75. b = b*a;
  76. i = i+1;
  77. }
  78. } else {
  79. // naive2:
  80. // floating-point representation with smooth precision reduction
  81. var cl_LF eps = scale_float(b,-(sintC)d-10);
  82. loop {
  83. var cl_LF new_sum = sum + LF_to_LF(b/(cl_I)i,actuallen); // (+ sum (/ b i))
  84. if (new_sum == sum) // = sum ?
  85. break; // ja -> Potenzreihe abbrechen
  86. sum = new_sum;
  87. b = cl_LF_shortenwith(b,eps);
  88. b = b*a;
  89. i = i+1;
  90. }
  91. }
  92. return scale_float(sum,k); // sum als Ergebnis, wegen Rekursion noch mal 2^k
  93. } else {
  94. var cl_LF z = y / (x+cl_float(1,x));
  95. // Potenzreihe atanh(z) anwenden:
  96. var int i = 1;
  97. var cl_LF a = square(z); // a = x^2
  98. var cl_LF b = cl_float(1,x); // b := (float 1 x)
  99. var cl_LF sum = cl_float(0,x); // sum := (float 0 x)
  100. if (0) {
  101. // naive1:
  102. // floating-point representation
  103. loop {
  104. var cl_LF new_sum = sum + b / (cl_I)i; // (+ sum (/ b i))
  105. if (new_sum == sum) // = sum ?
  106. break; // ja -> Potenzreihe abbrechen
  107. sum = new_sum;
  108. b = b*a;
  109. i = i+2;
  110. }
  111. } else {
  112. // naive2:
  113. // floating-point representation with smooth precision reduction
  114. var cl_LF eps = scale_float(b,-(sintC)d-10);
  115. loop {
  116. var cl_LF new_sum = sum + LF_to_LF(b/(cl_I)i,actuallen); // (+ sum (/ b i))
  117. if (new_sum == sum) // = sum ?
  118. break; // ja -> Potenzreihe abbrechen
  119. sum = new_sum;
  120. b = cl_LF_shortenwith(b,eps);
  121. b = b*a;
  122. i = i+2;
  123. }
  124. }
  125. return scale_float(sum*z,k+1); // 2*sum*z als Ergebnis, wegen Rekursion noch mal 2^k
  126. }
  127. }}
  128. // Bit complexity (N = length(x)): O(N^(1/2)*M(N)).
  129. const cl_F lnx_naive (const cl_F& x)
  130. {
  131. if (longfloatp(x)) {
  132. DeclareType(cl_LF,x);
  133. return lnx_naive(x);
  134. }
  135. var cl_F y = x-cl_float(1,x);
  136. if (zerop(y)) // y=0.0 -> y als Ergebnis
  137. return y;
  138. var uintC d = float_digits(x);
  139. var sintE e = float_exponent(y);
  140. if (e <= -(sintC)d) // e <= -d ?
  141. return y; // ja -> y als Ergebnis
  142. { Mutable(cl_F,x);
  143. var uintL k = 0; // Rekursionszähler k:=0
  144. // Bei e <= -1-floor(sqrt(d)) kann die Potenzreihe angewandt werden.
  145. var sintL e_limit = -1-isqrtC(d); // -1-floor(sqrt(d))
  146. while (e > e_limit) {
  147. // e > -1-floor(sqrt(d)) -> muß |y| verkleinern.
  148. x = sqrt(x); // x := (sqrt x)
  149. y = x-cl_float(1,x); // y := (- x 1) und
  150. e = float_exponent(y); // e neu berechnen
  151. k = k+1; // k:=k+1
  152. }
  153. // Potenzreihe anwenden:
  154. var int i = 1;
  155. var cl_F sum = cl_float(0,x); // sum := (float 0 x)
  156. var cl_F a = -y;
  157. var cl_F b = y;
  158. loop {
  159. var cl_F new_sum = sum + b/(cl_I)i; // (+ sum (/ b i))
  160. if (new_sum == sum) // = sum ?
  161. break; // ja -> Potenzreihe abbrechen
  162. sum = new_sum;
  163. b = b*a;
  164. i = i+1;
  165. }
  166. return scale_float(sum,k); // sum als Ergebnis, wegen Rekursion noch mal 2^k
  167. }}
  168. // Bit complexity (N = length(x)): O(N^(1/2)*M(N)).
  169. const cl_LF lnx_ratseries (const cl_LF& x)
  170. {
  171. // Method:
  172. // Based on the same ideas as expx_ratseries.
  173. // y := 0.
  174. // Loop
  175. // [x*exp(y) is invariant]
  176. // x' := x-1. If x' = 0, terminate the loop.
  177. // Choose approximation y' of log(x) = log(1+x'):
  178. // If |x'| >= 1/2, set y' = 1/2 * sign(x').
  179. // If |x'| < 2^-n with n maximal, set
  180. // y' = truncate(x'*2^(2n))/2^(2n).
  181. // Set y := y + y' and x := x*exp(-y').
  182. var uintC len = TheLfloat(x)->len;
  183. { Mutable(cl_LF,x);
  184. var cl_LF y = cl_I_to_LF(0,len);
  185. loop {
  186. var cl_LF x1 = x + cl_I_to_LF(-1,len);
  187. var cl_idecoded_float x1_ = integer_decode_float(x1);
  188. // x1 = (-1)^sign * 2^exponent * mantissa
  189. if (zerop(x1_.mantissa))
  190. break;
  191. var uintC lm = integer_length(x1_.mantissa);
  192. var uintE me = cl_I_to_UE(- x1_.exponent);
  193. var cl_I p;
  194. var uintE lq;
  195. var bool last_step = false;
  196. if (lm >= me) { // |x'| >= 1/2 ?
  197. p = x1_.sign; // 1 or -1
  198. lq = 1;
  199. } else {
  200. var uintE n = me - lm; // |x'| < 2^-n with n maximal
  201. // Set p to the first n bits of |x'|:
  202. if (lm > n) {
  203. p = x1_.mantissa >> (lm - n);
  204. lq = 2*n;
  205. } else {
  206. p = x1_.mantissa;
  207. lq = lm + n;
  208. }
  209. if (minusp(x1_.sign)) { p = -p; }
  210. // If 2*n >= lm = intDsize*len, then within our
  211. // precision exp(-y') = 1-y', (because |y'^2| < 2^-lm),
  212. // and we know a priori that the iteration will stop
  213. // after the next big multiplication. This saves one
  214. // big multiplication at the end.
  215. if (2*n >= lm)
  216. last_step = true;
  217. }
  218. y = y + scale_float(cl_I_to_LF(p,len),-(sintE)lq);
  219. if (last_step)
  220. break;
  221. x = x * cl_exp_aux(-p,lq,len);
  222. }
  223. return y;
  224. }}
  225. // Bit complexity (N = length(x)): O(log(N)^2*M(N)).
  226. // Timings of the above algorithms, on an i486 33 MHz, running Linux,
  227. // applied to x = sqrt(sqrt(2)) = 1.189...
  228. // N ln(1+y) ln(1+y) atanh z atanh z exp
  229. // naive1 naive2 naive1 naive2 ratseries
  230. // 10 0.019 0.016 0.013 0.012 0.036
  231. // 25 0.077 0.056 0.057 0.040 0.087
  232. // 50 0.30 0.21 0.23 0.15 0.21
  233. // 100 1.24 0.81 0.92 0.59 0.61
  234. // 250 8.8 5.8 6.3 4.3 2.77
  235. // 500 43.9 28.8 29.7 21.0 9.8
  236. // 1000 223 149 144 107 30
  237. // ==> ratseries faster for N >= 110. (N = length before extended by the caller.)
  238. } // namespace cln