v / vlib / math / exp.v
202 lines · 183 sloc · 4.65 KB · 008aaad99981918c51194d7aaaaaccb4c258f244
Raw
1module math
2
3import math.internal
4
5const f64_max_exp = f64(1024)
6const f64_min_exp = f64(-1021)
7const threshold = 7.09782712893383973096e+02 // 0x40862E42FEFA39EF
8
9const ln2_x56 = 3.88162421113569373274e+01 // 0x4043687a9f1af2b1
10
11const ln2_halfx3 = 1.03972077083991796413e+00 // 0x3ff0a2b23f3bab73
12
13const ln2_half = 3.46573590279972654709e-01 // 0x3fd62e42fefa39ef
14
15const ln2hi = 6.93147180369123816490e-01 // 0x3fe62e42fee00000
16
17const ln2lo = 1.90821492927058770002e-10 // 0x3dea39ef35793c76
18
19const inv_ln2 = 1.44269504088896338700e+00 // 0x3ff71547652b82fe
20
21// scaled coefficients related to expm1
22const expm1_q1 = -3.33333333333331316428e-02 // 0xBFA11111111110F4
23
24const expm1_q2 = 1.58730158725481460165e-03 // 0x3F5A01A019FE5585
25
26const expm1_q3 = -7.93650757867487942473e-05 // 0xBF14CE199EAADBB7
27
28const expm1_q4 = 4.00821782732936239552e-06 // 0x3ED0CFCA86E65239
29
30const expm1_q5 = -2.01099218183624371326e-07
31
32// exp returns e**x, the base-e exponential of x.
33//
34// special cases are:
35// exp(+inf) = +inf
36// exp(nan) = nan
37// Very large values overflow to 0 or +inf.
38// Very small values underflow to 1.
39pub fn exp(x f64) f64 {
40 log2e := 1.44269504088896338700e+00
41 overflow := 7.09782712893383973096e+02
42 underflow := -7.45133219101941108420e+02
43 near_zero := 1.0 / (1 << 28) // 2**-28
44 // special cases
45 if is_nan(x) || is_inf(x, 1) {
46 return x
47 }
48 if is_inf(x, -1) {
49 return 0.0
50 }
51 if x > overflow {
52 return inf(1)
53 }
54 if x < underflow {
55 return 0.0
56 }
57 if -near_zero < x && x < near_zero {
58 return 1.0 + x
59 }
60 // reduce; computed as r = hi - lo for extra precision.
61 mut k := 0
62 if x < 0 {
63 k = int(log2e * x - 0.5)
64 }
65 if x > 0 {
66 k = int(log2e * x + 0.5)
67 }
68 hi := x - f64(k) * ln2hi
69 lo := f64(k) * ln2lo
70 // compute
71 return expmulti(hi, lo, k)
72}
73
74// exp2 returns 2**x, the base-2 exponential of x.
75//
76// special cases are the same as exp.
77pub fn exp2(x f64) f64 {
78 overflow := 1.0239999999999999e+03
79 underflow := -1.0740e+03
80 if is_nan(x) || is_inf(x, 1) {
81 return x
82 }
83 if is_inf(x, -1) {
84 return 0
85 }
86 if x > overflow {
87 return inf(1)
88 }
89 if x < underflow {
90 return 0
91 }
92 // argument reduction; x = r×lg(e) + k with |r| ≤ ln(2)/2.
93 // computed as r = hi - lo for extra precision.
94 mut k := 0
95 if x > 0 {
96 k = int(x + 0.5)
97 }
98 if x < 0 {
99 k = int(x - 0.5)
100 }
101 mut t := x - f64(k)
102 hi := t * ln2hi
103 lo := -t * ln2lo
104 // compute
105 return expmulti(hi, lo, k)
106}
107
108// ldexp calculates frac*(2**exp)
109pub fn ldexp(frac f64, exp int) f64 {
110 return scalbn(frac, exp)
111}
112
113// frexp breaks f into a normalized fraction
114// and an integral power of two.
115// It returns frac and exp satisfying f == frac × 2**exp,
116// with the absolute value of frac in the interval [½, 1).
117//
118// special cases are:
119// frexp(±0) = ±0, 0
120// frexp(±inf) = ±inf, 0
121// frexp(nan) = nan, 0
122// pub fn frexp(f f64) (f64, int) {
123// mut y := f64_bits(x)
124// ee := int((y >> 52) & 0x7ff)
125// // special cases
126// if ee == 0 {
127// if x != 0.0 {
128// x1p64 := f64_from_bits(0x43f0000000000000)
129// z,e_ := frexp(x * x1p64)
130// return z,e_ - 64
131// }
132// return x,0
133// } else if ee == 0x7ff {
134// return x,0
135// }
136// e_ := ee - 0x3fe
137// y &= 0x800fffffffffffff
138// y |= 0x3fe0000000000000
139// return f64_from_bits(y),e_
140pub fn frexp(x f64) (f64, int) {
141 mut y := f64_bits(x)
142 ee := int((y >> 52) & 0x7ff)
143 if ee == 0 {
144 if x != 0.0 {
145 x1p64 := f64_from_bits(u64(0x43f0000000000000))
146 z, e_ := frexp(x * x1p64)
147 return z, e_ - 64
148 }
149 return x, 0
150 } else if ee == 0x7ff {
151 return x, 0
152 }
153 e_ := ee - 0x3fe
154 y &= u64(0x800fffffffffffff)
155 y |= u64(0x3fe0000000000000)
156 return f64_from_bits(y), e_
157}
158
159// expm1 calculates e**x - 1
160// special cases are:
161// expm1(+inf) = +inf
162// expm1(-inf) = -1
163// expm1(nan) = nan
164pub fn expm1(x f64) f64 {
165 if is_inf(x, 1) || is_nan(x) {
166 return x
167 }
168 if is_inf(x, -1) {
169 return f64(-1)
170 }
171 // FIXME: this should be improved
172 if abs(x) < ln2 { // Compute the taylor series S = x + (1/2!) x^2 + (1/3!) x^3 + ...
173 mut i := 1.0
174 mut sum := x
175 mut term := x / 1.0
176 i++
177 term *= x / f64(i)
178 sum += term
179 for abs(term) > abs(sum) * internal.f64_epsilon {
180 i++
181 term *= x / f64(i)
182 sum += term
183 }
184 return sum
185 } else {
186 return exp(x) - 1
187 }
188}
189
190fn expmulti(hi f64, lo f64, k int) f64 {
191 exp_p1 := 1.66666666666666657415e-01 // 0x3FC55555; 0x55555555
192 exp_p2 := -2.77777777770155933842e-03 // 0xBF66C16C; 0x16BEBD93
193 exp_p3 := 6.61375632143793436117e-05 // 0x3F11566A; 0xAF25DE2C
194 exp_p4 := -1.65339022054652515390e-06 // 0xBEBBBD41; 0xC5D26BF1
195 exp_p5 := 4.13813679705723846039e-08 // 0x3E663769; 0x72BEA4D0
196 r := hi - lo
197 t := r * r
198 c := r - t * (exp_p1 + t * (exp_p2 + t * (exp_p3 + t * (exp_p4 + t * exp_p5))))
199 y := 1 - ((lo - (r * c) / (2 - c)) - hi)
200 // TODO(rsc): make sure ldexp can handle boundary k
201 return ldexp(y, k)
202}
203