|
1 |
| -/* origin: FreeBSD /usr/src/lib/msun/src/e_logf.c */ |
2 |
| -/* |
3 |
| - * Conversion to float by Ian Lance Taylor, Cygnus Support, [email protected]. |
4 |
| - */ |
5 |
| -/* |
6 |
| - * ==================================================== |
7 |
| - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. |
8 |
| - * |
9 |
| - * Developed at SunPro, a Sun Microsystems, Inc. business. |
10 |
| - * Permission to use, copy, modify, and distribute this |
11 |
| - * software is freely granted, provided that this notice |
12 |
| - * is preserved. |
13 |
| - * ==================================================== |
14 |
| - */ |
| 1 | +const LOGF_TABLE_BITS: u32 = 4; |
| 2 | +const T: [(f64, f64); 16] = [(1.398907162146528e0, -3.3569133332882284e-1), |
| 3 | + (1.3403141896637998e0, -2.929040563774074e-1), |
| 4 | + (1.286432210124115e0, -2.518726580937369e-1), |
| 5 | + (1.2367150214269895e0, -2.1245868807117255e-1), |
| 6 | + (1.1906977166711752e0, -1.7453945183745634e-1), |
| 7 | + (1.1479821020556429e0, -1.380057072319758e-1), |
| 8 | + (1.1082251448272158e0, -1.0275976698545139e-1), |
| 9 | + (1.0711297413057381e0, -6.871392447020525e-2), |
| 10 | + (1.036437278977283e0, -3.57891387398228e-2), |
| 11 | + (1e0, 0e0), |
| 12 | + (9.492859795739057e-1, 5.204517742929496e-2), |
| 13 | + (8.951049428609004e-1, 1.1081431298787942e-1), |
| 14 | + (8.476821620351103e-1, 1.652495223695143e-1), |
| 15 | + (8.050314851692001e-1, 2.1687389031699977e-1), |
| 16 | + (7.664671008843108e-1, 2.659635028121397e-1), |
| 17 | + (7.31428603316328e-1, 3.127556664073557e-1)]; |
15 | 18 |
|
16 |
| -const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ |
17 |
| -const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ |
18 |
| -/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ |
19 |
| -const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24*/ |
20 |
| -const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ |
21 |
| -const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ |
22 |
| -const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ |
| 19 | +const A: [f64; 3] = [-2.5089342214237154e-1, 3.33456765744066e-1, -4.999997485802103e-1]; |
| 20 | +const LN2: f64 = 6.931471805599453e-1; |
| 21 | +const N: u32 = (1 << LOGF_TABLE_BITS); |
| 22 | +const OFF: u32 = 0x3f330000; |
23 | 23 |
|
24 | 24 | #[inline]
|
25 | 25 | #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
26 |
| -pub fn logf(mut x: f32) -> f32 { |
27 |
| - let x1p25 = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 |
28 |
| - |
| 26 | +pub fn logf(x: f32) -> f32 { |
29 | 27 | let mut ix = x.to_bits();
|
30 |
| - let mut k = 0i32; |
31 | 28 |
|
32 |
| - if (ix < 0x00800000) || ((ix >> 31) != 0) { |
33 |
| - /* x < 2**-126 */ |
34 |
| - if ix << 1 == 0 { |
35 |
| - return -1. / (x * x); /* log(+-0)=-inf */ |
36 |
| - } |
37 |
| - if (ix >> 31) != 0 { |
38 |
| - return (x - x) / 0.; /* log(-#) = NaN */ |
39 |
| - } |
40 |
| - /* subnormal number, scale up x */ |
41 |
| - k -= 25; |
42 |
| - x *= x1p25; |
43 |
| - ix = x.to_bits(); |
44 |
| - } else if ix >= 0x7f800000 { |
45 |
| - return x; |
46 |
| - } else if ix == 0x3f800000 { |
| 29 | + /* Fix sign of zero with downward rounding when x==1. */ |
| 30 | + if ix == 0x3f800000 { |
47 | 31 | return 0.;
|
48 | 32 | }
|
| 33 | + if ix - 0x00800000 >= 0x7f800000 - 0x00800000 { |
| 34 | + /* x < 0x1p-126 or inf or nan. */ |
| 35 | + if ix * 2 == 0 { |
| 36 | + return -1. / 0.; |
| 37 | + } |
| 38 | + if ix == 0x7f800000 { /* log(inf) == inf. */ |
| 39 | + return x; |
| 40 | + } |
| 41 | + if (ix & 0x80000000) != 0 || ix * 2 >= 0xff000000 { |
| 42 | + return (x - x) / (x - x); |
| 43 | + } |
| 44 | + /* x is subnormal, normalize it. */ |
| 45 | + ix = f32::to_bits(x * 8.388608e6); |
| 46 | + ix -= 23 << 23; |
| 47 | + } |
| 48 | + |
| 49 | + /* x = 2^k z; where z is in range [OFF,2*OFF] and exact. |
| 50 | + The range is split into N subintervals. |
| 51 | + The ith subinterval contains z and c is near its center. */ |
| 52 | + let tmp = ix - OFF; |
| 53 | + let i = (tmp >> (23 - LOGF_TABLE_BITS)) % N; |
| 54 | + let k = tmp as i32 >> 23; /* arithmetic shift */ |
| 55 | + let iz = ix - (tmp & 0x1ff << 23); |
| 56 | + let (invc, logc) = T[i as usize]; |
| 57 | + let z = f32::from_bits(iz) as f64; |
49 | 58 |
|
50 |
| - /* reduce x into [sqrt(2)/2, sqrt(2)] */ |
51 |
| - ix += 0x3f800000 - 0x3f3504f3; |
52 |
| - k += ((ix >> 23) as i32) - 0x7f; |
53 |
| - ix = (ix & 0x007fffff) + 0x3f3504f3; |
54 |
| - x = f32::from_bits(ix); |
| 59 | + /* log(x) = log1p(z/c-1) + log(c) + k*Ln2 */ |
| 60 | + let r = z * invc - 1.; |
| 61 | + let y0 = logc + k as f64 * LN2; |
55 | 62 |
|
56 |
| - let f = x - 1.; |
57 |
| - let s = f / (2. + f); |
58 |
| - let z = s * s; |
59 |
| - let w = z * z; |
60 |
| - let t1 = w * (LG2 + w * LG4); |
61 |
| - let t2 = z * (LG1 + w * LG3); |
62 |
| - let r = t2 + t1; |
63 |
| - let hfsq = 0.5 * f * f; |
64 |
| - let dk = k as f32; |
65 |
| - s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI |
| 63 | + /* Pipelined polynomial evaluation to approximate log1p(r). */ |
| 64 | + let r2 = r * r; |
| 65 | + let mut y = A[1] * r + A[2]; |
| 66 | + y = A[0] * r2 + y; |
| 67 | + y = y * r2 + (y0 + r); |
| 68 | + return y as f32; |
66 | 69 | }
|
0 commit comments