| 1 | /* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2f.c */ |
| 2 | /* |
| 3 | * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. |
| 4 | * Debugged and optimized by Bruce D. Evans. |
| 5 | */ |
| 6 | /* |
| 7 | * ==================================================== |
| 8 | * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. |
| 9 | * |
| 10 | * Developed at SunPro, a Sun Microsystems, Inc. business. |
| 11 | * Permission to use, copy, modify, and distribute this |
| 12 | * software is freely granted, provided that this notice |
| 13 | * is preserved. |
| 14 | * ==================================================== |
| 15 | */ |
| 16 | |
| 17 | use core::f64; |
| 18 | |
| 19 | use super::rem_pio2_large; |
| 20 | |
| 21 | const TOINT: f64 = 1.5 / f64::EPSILON; |
| 22 | |
| 23 | /// 53 bits of 2/pi |
| 24 | const INV_PIO2: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ |
| 25 | /// first 25 bits of pi/2 |
| 26 | const PIO2_1: f64 = 1.57079631090164184570e+00; /* 0x3FF921FB, 0x50000000 */ |
| 27 | /// pi/2 - pio2_1 |
| 28 | const PIO2_1T: f64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ |
| 29 | |
| 30 | /// Return the remainder of x rem pi/2 in *y |
| 31 | /// |
| 32 | /// use double precision for everything except passing x |
| 33 | /// use __rem_pio2_large() for large x |
| 34 | #[cfg_attr (all(test, assert_no_panic), no_panic::no_panic)] |
| 35 | pub(crate) fn rem_pio2f(x: f32) -> (i32, f64) { |
| 36 | let x64 = x as f64; |
| 37 | |
| 38 | let mut tx: [f64; 1] = [0.]; |
| 39 | let mut ty: [f64; 1] = [0.]; |
| 40 | |
| 41 | let ix = x.to_bits() & 0x7fffffff; |
| 42 | /* 25+53 bit pi is good enough for medium size */ |
| 43 | if ix < 0x4dc90fdb { |
| 44 | /* |x| ~< 2^28*(pi/2), medium size */ |
| 45 | /* Use a specialized rint() to get fn. Assume round-to-nearest. */ |
| 46 | let tmp = x64 * INV_PIO2 + TOINT; |
| 47 | // force rounding of tmp to it's storage format on x87 to avoid |
| 48 | // excess precision issues. |
| 49 | #[cfg (all(target_arch = "x86" , not(target_feature = "sse2" )))] |
| 50 | let tmp = force_eval!(tmp); |
| 51 | let f_n = tmp - TOINT; |
| 52 | return (f_n as i32, x64 - f_n * PIO2_1 - f_n * PIO2_1T); |
| 53 | } |
| 54 | if ix >= 0x7f800000 { |
| 55 | /* x is inf or NaN */ |
| 56 | return (0, x64 - x64); |
| 57 | } |
| 58 | /* scale x into [2^23, 2^24-1] */ |
| 59 | let sign = (x.to_bits() >> 31) != 0; |
| 60 | let e0 = ((ix >> 23) - (0x7f + 23)) as i32; /* e0 = ilogb(|x|)-23, positive */ |
| 61 | tx[0] = f32::from_bits(ix - (e0 << 23) as u32) as f64; |
| 62 | let n = rem_pio2_large(&tx, &mut ty, e0, 0); |
| 63 | if sign { |
| 64 | return (-n, -ty[0]); |
| 65 | } |
| 66 | (n, ty[0]) |
| 67 | } |
| 68 | |