|
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