/rust/registry/src/index.crates.io-1949cf8c6b5b557f/libm-0.2.11/src/math/log1p.rs
Line  | Count  | Source  | 
1  |  | /* origin: FreeBSD /usr/src/lib/msun/src/s_log1p.c */  | 
2  |  | /*  | 
3  |  |  * ====================================================  | 
4  |  |  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.  | 
5  |  |  *  | 
6  |  |  * Developed at SunPro, a Sun Microsystems, Inc. business.  | 
7  |  |  * Permission to use, copy, modify, and distribute this  | 
8  |  |  * software is freely granted, provided that this notice  | 
9  |  |  * is preserved.  | 
10  |  |  * ====================================================  | 
11  |  |  */  | 
12  |  | /* double log1p(double x)  | 
13  |  |  * Return the natural logarithm of 1+x.  | 
14  |  |  *  | 
15  |  |  * Method :  | 
16  |  |  *   1. Argument Reduction: find k and f such that  | 
17  |  |  *                      1+x = 2^k * (1+f),  | 
18  |  |  *         where  sqrt(2)/2 < 1+f < sqrt(2) .  | 
19  |  |  *  | 
20  |  |  *      Note. If k=0, then f=x is exact. However, if k!=0, then f  | 
21  |  |  *      may not be representable exactly. In that case, a correction  | 
22  |  |  *      term is need. Let u=1+x rounded. Let c = (1+x)-u, then  | 
23  |  |  *      log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u),  | 
24  |  |  *      and add back the correction term c/u.  | 
25  |  |  *      (Note: when x > 2**53, one can simply return log(x))  | 
26  |  |  *  | 
27  |  |  *   2. Approximation of log(1+f): See log.c  | 
28  |  |  *  | 
29  |  |  *   3. Finally, log1p(x) = k*ln2 + log(1+f) + c/u. See log.c  | 
30  |  |  *  | 
31  |  |  * Special cases:  | 
32  |  |  *      log1p(x) is NaN with signal if x < -1 (including -INF) ;  | 
33  |  |  *      log1p(+INF) is +INF; log1p(-1) is -INF with signal;  | 
34  |  |  *      log1p(NaN) is that NaN with no signal.  | 
35  |  |  *  | 
36  |  |  * Accuracy:  | 
37  |  |  *      according to an error analysis, the error is always less than  | 
38  |  |  *      1 ulp (unit in the last place).  | 
39  |  |  *  | 
40  |  |  * Constants:  | 
41  |  |  * The hexadecimal values are the intended ones for the following  | 
42  |  |  * constants. The decimal values may be used, provided that the  | 
43  |  |  * compiler will convert from decimal to binary accurately enough  | 
44  |  |  * to produce the hexadecimal values shown.  | 
45  |  |  *  | 
46  |  |  * Note: Assuming log() return accurate answer, the following  | 
47  |  |  *       algorithm can be used to compute log1p(x) to within a few ULP:  | 
48  |  |  *  | 
49  |  |  *              u = 1+x;  | 
50  |  |  *              if(u==1.0) return x ; else  | 
51  |  |  *                         return log(u)*(x/(u-1.0));  | 
52  |  |  *  | 
53  |  |  *       See HP-15C Advanced Functions Handbook, p.193.  | 
54  |  |  */  | 
55  |  |  | 
56  |  | use core::f64;  | 
57  |  |  | 
58  |  | const LN2_HI: f64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */  | 
59  |  | const LN2_LO: f64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */  | 
60  |  | const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */  | 
61  |  | const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */  | 
62  |  | const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */  | 
63  |  | const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */  | 
64  |  | const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */  | 
65  |  | const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */  | 
66  |  | const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */  | 
67  |  |  | 
68  |  | /// The natural logarithm of 1+`x` (f64).  | 
69  |  | #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]  | 
70  | 0  | pub fn log1p(x: f64) -> f64 { | 
71  | 0  |     let mut ui: u64 = x.to_bits();  | 
72  |  |     let hfsq: f64;  | 
73  | 0  |     let mut f: f64 = 0.;  | 
74  | 0  |     let mut c: f64 = 0.;  | 
75  |  |     let s: f64;  | 
76  |  |     let z: f64;  | 
77  |  |     let r: f64;  | 
78  |  |     let w: f64;  | 
79  |  |     let t1: f64;  | 
80  |  |     let t2: f64;  | 
81  |  |     let dk: f64;  | 
82  |  |     let hx: u32;  | 
83  |  |     let mut hu: u32;  | 
84  |  |     let mut k: i32;  | 
85  |  |  | 
86  | 0  |     hx = (ui >> 32) as u32;  | 
87  | 0  |     k = 1;  | 
88  | 0  |     if hx < 0x3fda827a || (hx >> 31) > 0 { | 
89  |  |         /* 1+x < sqrt(2)+ */  | 
90  | 0  |         if hx >= 0xbff00000 { | 
91  |  |             /* x <= -1.0 */  | 
92  | 0  |             if x == -1. { | 
93  | 0  |                 return x / 0.0; /* log1p(-1) = -inf */  | 
94  | 0  |             }  | 
95  | 0  |             return (x - x) / 0.0; /* log1p(x<-1) = NaN */  | 
96  | 0  |         }  | 
97  | 0  |         if hx << 1 < 0x3ca00000 << 1 { | 
98  |  |             /* |x| < 2**-53 */  | 
99  |  |             /* underflow if subnormal */  | 
100  | 0  |             if (hx & 0x7ff00000) == 0 { | 
101  | 0  |                 force_eval!(x as f32);  | 
102  | 0  |             }  | 
103  | 0  |             return x;  | 
104  | 0  |         }  | 
105  | 0  |         if hx <= 0xbfd2bec4 { | 
106  | 0  |             /* sqrt(2)/2- <= 1+x < sqrt(2)+ */  | 
107  | 0  |             k = 0;  | 
108  | 0  |             c = 0.;  | 
109  | 0  |             f = x;  | 
110  | 0  |         }  | 
111  | 0  |     } else if hx >= 0x7ff00000 { | 
112  | 0  |         return x;  | 
113  | 0  |     }  | 
114  | 0  |     if k > 0 { | 
115  | 0  |         ui = (1. + x).to_bits();  | 
116  | 0  |         hu = (ui >> 32) as u32;  | 
117  | 0  |         hu += 0x3ff00000 - 0x3fe6a09e;  | 
118  | 0  |         k = (hu >> 20) as i32 - 0x3ff;  | 
119  |  |         /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */  | 
120  | 0  |         if k < 54 { | 
121  | 0  |             c = if k >= 2 { 1. - (f64::from_bits(ui) - x) } else { x - (f64::from_bits(ui) - 1.) }; | 
122  | 0  |             c /= f64::from_bits(ui);  | 
123  | 0  |         } else { | 
124  | 0  |             c = 0.;  | 
125  | 0  |         }  | 
126  |  |         /* reduce u into [sqrt(2)/2, sqrt(2)] */  | 
127  | 0  |         hu = (hu & 0x000fffff) + 0x3fe6a09e;  | 
128  | 0  |         ui = (hu as u64) << 32 | (ui & 0xffffffff);  | 
129  | 0  |         f = f64::from_bits(ui) - 1.;  | 
130  | 0  |     }  | 
131  | 0  |     hfsq = 0.5 * f * f;  | 
132  | 0  |     s = f / (2.0 + f);  | 
133  | 0  |     z = s * s;  | 
134  | 0  |     w = z * z;  | 
135  | 0  |     t1 = w * (LG2 + w * (LG4 + w * LG6));  | 
136  | 0  |     t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7)));  | 
137  | 0  |     r = t2 + t1;  | 
138  | 0  |     dk = k as f64;  | 
139  | 0  |     s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI  | 
140  | 0  | }  |