/rust/registry/src/index.crates.io-1949cf8c6b5b557f/lexical-util-1.0.7/src/libm.rs
Line | Count | Source |
1 | | //! Float helpers for a `no_std` environment. |
2 | | //! |
3 | | //! These are adapted from libm, a port of musl libc's libm to Rust. |
4 | | //! libm can be found online [here](https://github.com/rust-lang/libm), |
5 | | //! and is similarly licensed under an Apache2.0/MIT license |
6 | | |
7 | | #![cfg(all(not(feature = "std"), any(feature = "parse-floats", feature = "write-floats")))] |
8 | | #![cfg_attr(any(), rustfmt::skip)] |
9 | | |
10 | | /// # Safety |
11 | | /// |
12 | | /// Safe as long as `e` is properly initialized. |
13 | | macro_rules! volatile { |
14 | | ($e:expr) => { |
15 | | // SAFETY: safe as long as `$e` has been properly initialized. |
16 | | unsafe { |
17 | | core::ptr::read_volatile(&$e); |
18 | | } |
19 | | }; |
20 | | } |
21 | | |
22 | | /// Floor (f64) |
23 | | /// |
24 | | /// Finds the nearest integer less than or equal to `x`. |
25 | 0 | pub(crate) fn floord(x: f64) -> f64 { |
26 | | const TOINT: f64 = 1. / f64::EPSILON; |
27 | | |
28 | 0 | let ui = x.to_bits(); |
29 | 0 | let e = ((ui >> 52) & 0x7ff) as i32; |
30 | | |
31 | 0 | if (e >= 0x3ff + 52) || (x == 0.) { |
32 | 0 | return x; |
33 | 0 | } |
34 | | /* y = int(x) - x, where int(x) is an integer neighbor of x */ |
35 | 0 | let y = if (ui >> 63) != 0 { |
36 | 0 | x - TOINT + TOINT - x |
37 | | } else { |
38 | 0 | x + TOINT - TOINT - x |
39 | | }; |
40 | | /* special case because of non-nearest rounding modes */ |
41 | 0 | if e < 0x3ff { |
42 | 0 | volatile!(y); |
43 | 0 | return if (ui >> 63) != 0 { |
44 | 0 | -1. |
45 | | } else { |
46 | 0 | 0. |
47 | | }; |
48 | 0 | } |
49 | 0 | if y > 0. { |
50 | 0 | x + y - 1. |
51 | | } else { |
52 | 0 | x + y |
53 | | } |
54 | 0 | } |
55 | | |
56 | | /// Floor (f32) |
57 | | /// |
58 | | /// Finds the nearest integer less than or equal to `x`. |
59 | 0 | pub(crate) fn floorf(x: f32) -> f32 { |
60 | 0 | let mut ui = x.to_bits(); |
61 | 0 | let e = (((ui >> 23) as i32) & 0xff) - 0x7f; |
62 | | |
63 | 0 | if e >= 23 { |
64 | 0 | return x; |
65 | 0 | } |
66 | 0 | if e >= 0 { |
67 | 0 | let m: u32 = 0x007fffff >> e; |
68 | 0 | if (ui & m) == 0 { |
69 | 0 | return x; |
70 | 0 | } |
71 | 0 | volatile!(x + f32::from_bits(0x7b800000)); |
72 | 0 | if ui >> 31 != 0 { |
73 | 0 | ui += m; |
74 | 0 | } |
75 | 0 | ui &= !m; |
76 | | } else { |
77 | 0 | volatile!(x + f32::from_bits(0x7b800000)); |
78 | 0 | if ui >> 31 == 0 { |
79 | 0 | ui = 0; |
80 | 0 | } else if ui << 1 != 0 { |
81 | 0 | return -1.0; |
82 | 0 | } |
83 | | } |
84 | 0 | f32::from_bits(ui) |
85 | 0 | } |
86 | | |
87 | | /* origin: FreeBSD /usr/src/lib/msun/src/e_log.c */ |
88 | | /* |
89 | | * ==================================================== |
90 | | * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. |
91 | | * |
92 | | * Developed at SunSoft, a Sun Microsystems, Inc. business. |
93 | | * Permission to use, copy, modify, and distribute this |
94 | | * software is freely granted, provided that this notice |
95 | | * is preserved. |
96 | | * ==================================================== |
97 | | */ |
98 | | /* log(x) |
99 | | * Return the logarithm of x |
100 | | * |
101 | | * Method : |
102 | | * 1. Argument Reduction: find k and f such that |
103 | | * x = 2^k * (1+f), |
104 | | * where sqrt(2)/2 < 1+f < sqrt(2) . |
105 | | * |
106 | | * 2. Approximation of log(1+f). |
107 | | * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) |
108 | | * = 2s + 2/3 s**3 + 2/5 s**5 + ....., |
109 | | * = 2s + s*R |
110 | | * We use a special Remez algorithm on [0,0.1716] to generate |
111 | | * a polynomial of degree 14 to approximate R The maximum error |
112 | | * of this polynomial approximation is bounded by 2**-58.45. In |
113 | | * other words, |
114 | | * 2 4 6 8 10 12 14 |
115 | | * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s |
116 | | * (the values of Lg1 to Lg7 are listed in the program) |
117 | | * and |
118 | | * | 2 14 | -58.45 |
119 | | * | Lg1*s +...+Lg7*s - R(z) | <= 2 |
120 | | * | | |
121 | | * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. |
122 | | * In order to guarantee error in log below 1ulp, we compute log |
123 | | * by |
124 | | * log(1+f) = f - s*(f - R) (if f is not too large) |
125 | | * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy) |
126 | | * |
127 | | * 3. Finally, log(x) = k*ln2 + log(1+f). |
128 | | * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) |
129 | | * Here ln2 is split into two floating point number: |
130 | | * ln2_hi + ln2_lo, |
131 | | * where n*ln2_hi is always exact for |n| < 2000. |
132 | | * |
133 | | * Special cases: |
134 | | * log(x) is NaN with signal if x < 0 (including -INF) ; |
135 | | * log(+INF) is +INF; log(0) is -INF with signal; |
136 | | * log(NaN) is that NaN with no signal. |
137 | | * |
138 | | * Accuracy: |
139 | | * according to an error analysis, the error is always less than |
140 | | * 1 ulp (unit in the last place). |
141 | | * |
142 | | * Constants: |
143 | | * The hexadecimal values are the intended ones for the following |
144 | | * constants. The decimal values may be used, provided that the |
145 | | * compiler will convert from decimal to binary accurately enough |
146 | | * to produce the hexadecimal values shown. |
147 | | */ |
148 | | |
149 | | #[allow(clippy::eq_op, clippy::excessive_precision)] // reason="values need to be exact under all conditions" |
150 | 0 | pub(crate) fn logd(mut x: f64) -> f64 { |
151 | | const LN2_HI: f64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ |
152 | | const LN2_LO: f64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ |
153 | | const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ |
154 | | const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ |
155 | | const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ |
156 | | const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ |
157 | | const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ |
158 | | const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ |
159 | | const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ |
160 | | |
161 | 0 | let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 |
162 | | |
163 | 0 | let mut ui = x.to_bits(); |
164 | 0 | let mut hx: u32 = (ui >> 32) as u32; |
165 | 0 | let mut k: i32 = 0; |
166 | | |
167 | 0 | if (hx < 0x00100000) || ((hx >> 31) != 0) { |
168 | | /* x < 2**-126 */ |
169 | 0 | if ui << 1 == 0 { |
170 | 0 | return -1. / (x * x); /* log(+-0)=-inf */ |
171 | 0 | } |
172 | 0 | if hx >> 31 != 0 { |
173 | 0 | return (x - x) / 0.0; /* log(-#) = NaN */ |
174 | 0 | } |
175 | | /* subnormal number, scale x up */ |
176 | 0 | k -= 54; |
177 | 0 | x *= x1p54; |
178 | 0 | ui = x.to_bits(); |
179 | 0 | hx = (ui >> 32) as u32; |
180 | 0 | } else if hx >= 0x7ff00000 { |
181 | 0 | return x; |
182 | 0 | } else if hx == 0x3ff00000 && ui << 32 == 0 { |
183 | 0 | return 0.; |
184 | 0 | } |
185 | | |
186 | | /* reduce x into [sqrt(2)/2, sqrt(2)] */ |
187 | 0 | hx += 0x3ff00000 - 0x3fe6a09e; |
188 | 0 | k += ((hx >> 20) as i32) - 0x3ff; |
189 | 0 | hx = (hx & 0x000fffff) + 0x3fe6a09e; |
190 | 0 | ui = ((hx as u64) << 32) | (ui & 0xffffffff); |
191 | 0 | x = f64::from_bits(ui); |
192 | | |
193 | 0 | let f: f64 = x - 1.0; |
194 | 0 | let hfsq: f64 = 0.5 * f * f; |
195 | 0 | let s: f64 = f / (2.0 + f); |
196 | 0 | let z: f64 = s * s; |
197 | 0 | let w: f64 = z * z; |
198 | 0 | let t1: f64 = w * (LG2 + w * (LG4 + w * LG6)); |
199 | 0 | let t2: f64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); |
200 | 0 | let r: f64 = t2 + t1; |
201 | 0 | let dk: f64 = k as f64; |
202 | 0 | s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI |
203 | 0 | } |
204 | | |
205 | | /* origin: FreeBSD /usr/src/lib/msun/src/e_logf.c */ |
206 | | /* |
207 | | * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. |
208 | | */ |
209 | | /* |
210 | | * ==================================================== |
211 | | * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. |
212 | | * |
213 | | * Developed at SunPro, a Sun Microsystems, Inc. business. |
214 | | * Permission to use, copy, modify, and distribute this |
215 | | * software is freely granted, provided that this notice |
216 | | * is preserved. |
217 | | * ==================================================== |
218 | | */ |
219 | | |
220 | | #[allow(clippy::eq_op, clippy::excessive_precision)] // reason="values need to be exact under all conditions" |
221 | 0 | pub(crate) fn logf(mut x: f32) -> f32 { |
222 | | const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ |
223 | | const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ |
224 | | /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ |
225 | | const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ |
226 | | const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ |
227 | | const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ |
228 | | const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ |
229 | | |
230 | 0 | let x1p25 = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 |
231 | | |
232 | 0 | let mut ix = x.to_bits(); |
233 | 0 | let mut k = 0i32; |
234 | | |
235 | 0 | if (ix < 0x00800000) || ((ix >> 31) != 0) { |
236 | | /* x < 2**-126 */ |
237 | 0 | if ix << 1 == 0 { |
238 | 0 | return -1. / (x * x); /* log(+-0)=-inf */ |
239 | 0 | } |
240 | 0 | if (ix >> 31) != 0 { |
241 | 0 | return (x - x) / 0.; /* log(-#) = NaN */ |
242 | 0 | } |
243 | | /* subnormal number, scale up x */ |
244 | 0 | k -= 25; |
245 | 0 | x *= x1p25; |
246 | 0 | ix = x.to_bits(); |
247 | 0 | } else if ix >= 0x7f800000 { |
248 | 0 | return x; |
249 | 0 | } else if ix == 0x3f800000 { |
250 | 0 | return 0.; |
251 | 0 | } |
252 | | |
253 | | /* reduce x into [sqrt(2)/2, sqrt(2)] */ |
254 | 0 | ix += 0x3f800000 - 0x3f3504f3; |
255 | 0 | k += ((ix >> 23) as i32) - 0x7f; |
256 | 0 | ix = (ix & 0x007fffff) + 0x3f3504f3; |
257 | 0 | x = f32::from_bits(ix); |
258 | | |
259 | 0 | let f = x - 1.; |
260 | 0 | let s = f / (2. + f); |
261 | 0 | let z = s * s; |
262 | 0 | let w = z * z; |
263 | 0 | let t1 = w * (LG2 + w * LG4); |
264 | 0 | let t2 = z * (LG1 + w * LG3); |
265 | 0 | let r = t2 + t1; |
266 | 0 | let hfsq = 0.5 * f * f; |
267 | 0 | let dk = k as f32; |
268 | 0 | s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI |
269 | 0 | } |