|
4 | 4 |
|
5 | 5 | package math
|
6 | 6 |
|
7 |
| - |
8 |
| -// The original C code, the long comment, and the constants |
9 |
| -// below are from FreeBSD's /usr/src/lib/msun/src/e_exp.c |
10 |
| -// and came with this notice. The go code is a simplified |
11 |
| -// version of the original C. |
12 |
| -// |
13 |
| -// ==================================================== |
14 |
| -// Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. |
15 |
| -// |
16 |
| -// Permission to use, copy, modify, and distribute this |
17 |
| -// software is freely granted, provided that this notice |
18 |
| -// is preserved. |
19 |
| -// ==================================================== |
20 |
| -// |
21 |
| -// |
22 |
| -// exp(x) |
23 |
| -// Returns the exponential of x. |
24 |
| -// |
25 |
| -// Method |
26 |
| -// 1. Argument reduction: |
27 |
| -// Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658. |
28 |
| -// Given x, find r and integer k such that |
29 |
| -// |
30 |
| -// x = k*ln2 + r, |r| <= 0.5*ln2. |
31 |
| -// |
32 |
| -// Here r will be represented as r = hi-lo for better |
33 |
| -// accuracy. |
34 |
| -// |
35 |
| -// 2. Approximation of exp(r) by a special rational function on |
36 |
| -// the interval [0,0.34658]: |
37 |
| -// Write |
38 |
| -// R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ... |
39 |
| -// We use a special Remes algorithm on [0,0.34658] to generate |
40 |
| -// a polynomial of degree 5 to approximate R. The maximum error |
41 |
| -// of this polynomial approximation is bounded by 2**-59. In |
42 |
| -// other words, |
43 |
| -// R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5 |
44 |
| -// (where z=r*r, and the values of P1 to P5 are listed below) |
45 |
| -// and |
46 |
| -// | 5 | -59 |
47 |
| -// | 2.0+P1*z+...+P5*z - R(z) | <= 2 |
48 |
| -// | | |
49 |
| -// The computation of exp(r) thus becomes |
50 |
| -// 2*r |
51 |
| -// exp(r) = 1 + ------- |
52 |
| -// R - r |
53 |
| -// r*R1(r) |
54 |
| -// = 1 + r + ----------- (for better accuracy) |
55 |
| -// 2 - R1(r) |
56 |
| -// where |
57 |
| -// 2 4 10 |
58 |
| -// R1(r) = r - (P1*r + P2*r + ... + P5*r ). |
59 |
| -// |
60 |
| -// 3. Scale back to obtain exp(x): |
61 |
| -// From step 1, we have |
62 |
| -// exp(x) = 2**k * exp(r) |
63 |
| -// |
64 |
| -// Special cases: |
65 |
| -// exp(INF) is INF, exp(NaN) is NaN; |
66 |
| -// exp(-INF) is 0, and |
67 |
| -// for finite argument, only exp(0)=1 is exact. |
68 |
| -// |
69 |
| -// Accuracy: |
70 |
| -// according to an error analysis, the error is always less than |
71 |
| -// 1 ulp (unit in the last place). |
72 |
| -// |
73 |
| -// Misc. info. |
74 |
| -// For IEEE double |
75 |
| -// if x > 7.09782712893383973096e+02 then exp(x) overflow |
76 |
| -// if x < -7.45133219101941108420e+02 then exp(x) underflow |
77 |
| -// |
78 |
| -// Constants: |
79 |
| -// The hexadecimal values are the intended ones for the following |
80 |
| -// constants. The decimal values may be used, provided that the |
81 |
| -// compiler will convert from decimal to binary accurately enough |
82 |
| -// to produce the hexadecimal values shown. |
83 |
| - |
84 | 7 | // Exp returns e**x, the base-e exponential of x.
|
85 | 8 | //
|
86 | 9 | // Special cases are:
|
87 | 10 | // Exp(+Inf) = +Inf
|
88 | 11 | // Exp(NaN) = NaN
|
89 | 12 | // Very large values overflow to 0 or +Inf.
|
90 | 13 | // Very small values underflow to 1.
|
91 |
| -func Exp(x float64) float64 { |
92 |
| - const ( |
93 |
| - Ln2Hi = 6.93147180369123816490e-01 |
94 |
| - Ln2Lo = 1.90821492927058770002e-10 |
95 |
| - Log2e = 1.44269504088896338700e+00 |
96 |
| - P1 = 1.66666666666666019037e-01 /* 0x3FC55555; 0x5555553E */ |
97 |
| - P2 = -2.77777777770155933842e-03 /* 0xBF66C16C; 0x16BEBD93 */ |
98 |
| - P3 = 6.61375632143793436117e-05 /* 0x3F11566A; 0xAF25DE2C */ |
99 |
| - P4 = -1.65339022054652515390e-06 /* 0xBEBBBD41; 0xC5D26BF1 */ |
100 |
| - P5 = 4.13813679705723846039e-08 /* 0x3E663769; 0x72BEA4D0 */ |
101 |
| - |
102 |
| - Overflow = 7.09782712893383973096e+02 |
103 |
| - Underflow = -7.45133219101941108420e+02 |
104 |
| - NearZero = 1.0 / (1 << 28) // 2**-28 |
105 |
| - ) |
106 |
| - |
107 |
| - // TODO(rsc): Remove manual inlining of IsNaN, IsInf |
108 |
| - // when compiler does it for us |
109 |
| - // special cases |
110 |
| - switch { |
111 |
| - case x != x || x > MaxFloat64: // IsNaN(x) || IsInf(x, 1): |
112 |
| - return x |
113 |
| - case x < -MaxFloat64: // IsInf(x, -1): |
114 |
| - return 0 |
115 |
| - case x > Overflow: |
116 |
| - return Inf(1) |
117 |
| - case x < Underflow: |
118 |
| - return 0 |
119 |
| - case -NearZero < x && x < NearZero: |
120 |
| - return 1 |
121 |
| - } |
122 |
| - |
123 |
| - // reduce; computed as r = hi - lo for extra precision. |
124 |
| - var k int |
125 |
| - switch { |
126 |
| - case x < 0: |
127 |
| - k = int(Log2e*x - 0.5) |
128 |
| - case x > 0: |
129 |
| - k = int(Log2e*x + 0.5) |
130 |
| - } |
131 |
| - hi := x - float64(k)*Ln2Hi |
132 |
| - lo := float64(k) * Ln2Lo |
133 |
| - r := hi - lo |
134 |
| - |
135 |
| - // compute |
136 |
| - t := r * r |
137 |
| - c := r - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))) |
138 |
| - y := 1 - ((lo - (r*c)/(2-c)) - hi) |
139 |
| - // TODO(rsc): make sure Ldexp can handle boundary k |
140 |
| - return Ldexp(y, k) |
141 |
| -} |
| 14 | +func Exp(x float64) float64 { return expGo(x) } |
0 commit comments