]> www.ginac.de Git - cln.git/blob - src/float/transcendental/cl_F_sinhx.cc
Get rid of CL_REQUIRE/CL_PROVIDE(cl_F_ln2_var).
[cln.git] / src / float / transcendental / cl_F_sinhx.cc
1 // sinhxbyx(), sinhx().
2
3 // General includes.
4 #include "cl_sysdep.h"
5
6 // Specification.
7 #include "cl_F_tran.h"
8
9
10 // Implementation.
11
12 #include "cln/float.h"
13 #include "cl_low.h"
14 #include "cl_F.h"
15 #include "cln/lfloat.h"
16 #include "cl_LF.h"
17 #include "cln/integer.h"
18
19 #include "cl_inline.h"
20 #include "cl_LF_zerop.cc"
21 #include "cl_LF_exponent.cc"
22
23 namespace cln {
24
25 // sinhxbyx is mainly for cl_SF, cl_FF, cl_DF, where we want to avoid underflow.
26
27 const cl_F sinhxbyx_naive (const cl_F& x)
28 {
29 // Methode:
30 // e := Exponent aus (decode-float x), d := (float-digits x)
31 // Bei x=0.0 oder e<=(1-d)/2 liefere 1.0
32 //   (denn bei e<=(1-d)/2 ist x^2/6 < x^2/4 < 2^(1-d)/4 = 2^(-d-1), also
33 //   1 <= sinh(x)/x = 1+x^2/6+... < 1+2^(-d-1), also 1 <= (sinh(x)/x)^2 < 1+2^(-d),
34 //   also ist (sinh(x)/x)^2, auf d Bits gerundet, gleich 1.0).
35 // Bei e<=-sqrt(d) verwende die Potenzreihe
36 //   sinh(x)/x = sum(j=0..inf,(x^2)^j/(2j+1)!):
37 //   a:=x^2, b:=1, i:=1, sum:=0,
38 //   while (/= sum (setq sum (+ sum b))) do b:=b*a/((i+1)*(i+2)), i:=i+2.
39 //   Ergebnis sum^2.
40 // Sonst setze y := x/2 = (scale-float x -1),
41 //   berechne rekursiv z:=(sinh(y)/y)^2 und liefere z*(1+y^2*z).
42 // [Die Grenze sqrt(d) ergibt sich so:
43 //  Man braucht bei der Potenzreihe mit x=2^-k etwa j Glieder, mit
44 //  k*j*ln 2 + j*(ln j - 1) = d, und der Aufwand beträgt etwa 2.8*(j/2)
45 //  Multiplikationen von d-Bit-Zahlen. Bei Halbierungen bis x=2^-k ist der
46 //  Gesamtaufwand etwa 2*(k+e)+1.4*j(k). Dieses minimieren nach k: Soll sein
47 //  -1.4 = d/dk j(k) = (d/dj k(j))^-1 = - j^2/(d+j)*ln 2, also j^2=2(d+j),
48 //  grob j=sqrt(2d) und damit k=sqrt(d).]
49 // Aufwand: asymptotisch d^2.5 .
50
51         if (zerop(x))
52                 return cl_float(1,x);
53         var uintC d = float_digits(x);
54         var sintE e = float_exponent(x);
55         if (e <= (1-(sintC)d)>>1) // e <= (1-d)/2 <==> e <= -ceiling((d-1)/2) ?
56                 return cl_float(1,x); // ja -> 1.0 als Ergebnis
57  {      Mutable(cl_F,x);
58         // Bei e <= -1-limit_slope*floor(sqrt(d)) kann die Potenzreihe
59         // angewandt werden. Wähle limit_slope = 13/32 = 0.4.
60         var sintL e_limit = -1-floor(isqrtC(d)*13,32); // -1-floor(sqrt(d))
61         if (e > e_limit) {
62                 // e > -1-limit_slope*floor(sqrt(d)) -> muß |x| verkleinern.
63                 x = scale_float(x,e_limit-e);
64                 // Neuer Exponent = e_limit.
65         }
66         var cl_F x2 = square(x);        // x^2
67         // Potenzreihe anwenden:
68         var cl_F a = x2; // a := x^2
69         var int i = 1;
70         var cl_F b = cl_float(1,x); // b := (float 1 x)
71         var cl_F sum = cl_float(0,x); // sum := (float 0 x)
72         loop {
73                 var cl_F new_sum = sum + b;
74                 if (new_sum == sum) // = sum ?
75                         break; // ja -> Potenzreihe abbrechen
76                 sum = new_sum;
77                 b = (b*a)/(cl_I)((i+1)*(i+2));
78                 i = i+2;
79         }
80         var cl_F z = square(sum); // sum^2 als Ergebnis
81         while (e > e_limit) {
82                 z = z + x2 * square(z);
83                 x2 = scale_float(x2,2); // x^2 := x^2*4
84                 e--;
85         }
86         return z;
87 }}
88 // Bit complexity (N = length(x)): O(N^(1/2)*M(N)).
89
90 const cl_LF sinhx_naive (const cl_LF& x)
91 {
92 // Methode:
93 // e := Exponent aus (decode-float x), d := (float-digits x)
94 // Bei x=0.0 oder e<=(1-d)/2 liefere x
95 //   (denn bei e<=(1-d)/2 ist x^2/6 < x^2/4 < 2^(1-d)/4 = 2^(-d-1), also
96 //   1 <= sinh(x)/x = 1+x^2/6+... < 1+2^(-d-1), also ist sinh(x)^2, auf d Bits
97 //   gerundet, gleich x).
98 // Bei e<=-sqrt(d) verwende die Potenzreihe
99 //   sinh(x) = sum(j=0..inf,x*(x^2)^j/(2j+1)!):
100 //   a:=x^2, b:=x, i:=1, sum:=0,
101 //   while (/= sum (setq sum (+ sum b))) do b:=b*a/((i+1)*(i+2)), i:=i+2.
102 //   Ergebnis sum^2.
103 // Sonst setze y := x/2 = (scale-float x -1),
104 //   berechne rekursiv z:=sinh(y)^2 und liefere 4*z*(1+z) = (1+2*z)^2-1.
105 // [Die Grenze sqrt(d) ergibt sich so:
106 //  Man braucht bei der Potenzreihe mit x=2^-k etwa j Glieder, mit
107 //  k*j*ln 2 + j*(ln j - 1) = d, und der Aufwand beträgt etwa 2.8*(j/2)
108 //  Multiplikationen von d-Bit-Zahlen. Bei Halbierungen bis x=2^-k ist der
109 //  Gesamtaufwand etwa 2*(k+e)+1.4*j(k). Dieses minimieren nach k: Soll sein
110 //  -1.4 = d/dk j(k) = (d/dj k(j))^-1 = - j^2/(d+j)*ln 2, also j^2=2(d+j),
111 //  grob j=sqrt(2d) und damit k=sqrt(d).]
112 // Aufwand: asymptotisch d^2.5 .
113
114         if (zerop_inline(x))
115                 return x;
116         var uintC actuallen = TheLfloat(x)->len;
117         var uintC d = float_digits(x);
118         var sintE e = float_exponent_inline(x);
119         if (e <= (1-(sintC)d)>>1) // e <= (1-d)/2 <==> e <= -ceiling((d-1)/2) ?
120                 return square(x); // ja -> x^2 als Ergebnis
121  {      Mutable(cl_LF,x);
122         var sintE ee = e;
123         // Bei e <= -1-limit_slope*floor(sqrt(d)) kann die Potenzreihe
124         // angewandt werden. Ein guter Wert für naive1 ist limit_slope = 0.6,
125         // für naive3 aber limit_slope = 0.5.
126         var sintL e_limit = -1-floor(isqrtC(d),2); // -1-floor(sqrt(d))
127         if (e > e_limit) {
128                 // e > -1-limit_slope*floor(sqrt(d)) -> muß |x| verkleinern.
129                 x = scale_float(x,e_limit-e);
130                 ee = e_limit; // Neuer Exponent = e_limit.
131         }
132         var cl_LF x2 = square(x); // x^2
133         // Potenzreihe anwenden:
134         var cl_LF powser_value;
135         var cl_LF a = x2; // a := x^2
136         var int i = 1;
137         if (0) {
138                 // naive1:
139                 // fixed-point representation
140                 d = d-ee; // fixed-point representation with d mantissa bits
141                 var cl_I b = round1(scale_float(x,d)); // b := x
142                 var cl_I sum = 0; // sum := (float 0 x)
143                 loop {
144                         if (b == 0) break;
145                         sum = sum + b;
146                         b = round1(round1(The(cl_LF)(b*a)),(cl_I)((i+1)*(i+2)));
147                         i = i+2;
148                 }
149                 powser_value = scale_float(cl_float(sum,x),-(sintC)d);
150         } else if (actuallen <= 7) { // Break-even-Point before extendsqrt: N<=6
151                 // naive2:
152                 // floating-point representation
153                 var cl_LF b = x; // b := x
154                 var cl_LF sum = cl_float(0,x); // sum := (float 0 x)
155                 loop {
156                         var cl_LF new_sum = sum + b;
157                         if (new_sum == sum) // = sum ?
158                                 break; // ja -> Potenzreihe abbrechen
159                         sum = new_sum;
160                         b = (b*a)/(cl_I)((i+1)*(i+2));
161                         i = i+2;
162                 }
163                 powser_value = sum;
164         } else {
165                 // naive3:
166                 // floating-point representation with smooth precision reduction
167                 var cl_LF b = x; // b := x
168                 var cl_LF eps = scale_float(b,-(sintC)d-10);
169                 var cl_LF sum = cl_float(0,x); // sum := (float 0 x)
170                 loop {
171                         var cl_LF new_sum = sum + LF_to_LF(b,actuallen);
172                         if (new_sum == sum) // = sum ?
173                                 break; // ja -> Potenzreihe abbrechen
174                         sum = new_sum;
175                         b = cl_LF_shortenwith(b,eps);
176                         b = (b*a)/(cl_I)((i+1)*(i+2));
177                         i = i+2;
178                 }
179                 powser_value = sum;
180         }
181         var cl_LF z = square(powser_value); // sinh^2 als Ergebnis
182         while (e > e_limit) {
183                 z = square(cl_float(1,x) + scale_float(z,1)) - cl_float(1,x); // z := (1+2*z)^2-1
184                 e--;
185         }
186         return z;
187 }}
188 // Bit complexity (N = length(x)): O(N^(1/2)*M(N)).
189
190 // Timings of the three variants, on an i486 33 MHz, running Linux,
191 // applied to x = sqrt(2)-1 = 0.414...
192 //   N     naive1  naive2  naive3  ratseries exp&recip
193 //    4     0.0055  0.0039  0.0041  0.021     0.0046
194 //    6     0.0073  0.0054  0.0054  0.029     0.0062
195 //    8     0.0093  0.0075  0.0070  0.036     0.0081
196 //   10     0.011   0.010   0.009   0.046     0.0011
197 //   25     0.041   0.046   0.033   0.133     0.043
198 //   50     0.14    0.18    0.12    0.36      0.16
199 //  100     0.56    0.70    0.43    1.12      0.61
200 //  250     3.5     4.5     2.7     5.3       3.3
201 //  500    14.9    19.4    11.4    19.0      11.4
202 // 1000    63      82      47      63        35
203 // 2500   328     381     243     261       143
204 // ==> naive2 fastest for N <= 6,
205 //     naive3 fastest for 6 <= N <= 500,
206 //     exp&recip (which uses exp's own ratseries) fastest for N >= 500.
207
208 }  // namespace cln