use super::P16E1;
impl P16E1 {
pub const fn exp(self) -> Self {
let ui_a = self.to_bits();
let mut f = ui_a as u64;
if ui_a < 28846 {
if ui_a < 192 {
return Self::ONE;
}
let mut s: i32;
if (f & 0x4000) != 0 {
s = 8;
while (f & 0x2000) != 0 {
f <<= 1;
s += 2;
}
} else {
s = 6;
while (f & 0x2000) == 0 {
f <<= 1;
s -= 2;
}
}
if (f & 0x1000) != 0 {
s += 1; }
f = (f & 0x0FFF) | 0x1000; f = ((if s < 0 { f >> -s } else { f << s }) * 48_408_813) >> 20;
let mut s = f >> 25; f = poly(f & 0x_01FF_FFFF); let mut bit = (s & 1) << 37; s >>= 1; f |= ((0x_0100_0000_0000 << s) - 0x_0080_0000_0000) | bit;
bit = 1_u64 << (24 + s); if ((f & bit) != 0) && (((f & (bit - 1)) != 0) || ((f & (bit << 1)) != 0)) {
f += bit;
}
return Self::from_bits((f >> (25 + s)) as u16); } else if ui_a > 36690 {
if ui_a > 65407 {
return Self::ONE;
}
let mut s: i32;
if (f & 0x4000) != 0 {
s = 7;
while (f & 0x2000) != 0 {
f <<= 1;
s -= 2;
}
} else {
s = 9;
while (f & 0x2000) == 0 {
f <<= 1;
s += 2;
}
}
if (f & 0x1000) != 0 {
s -= 1; }
f = (f & 0x0FFF) | 0x_01FF_E000; f = if s < 0 {
(f >> -s) | (0x_0200_0000 - (1 << (13 + s)))
} else {
(f << s) & 0x_01ff_ffff
};
f = (0x_0004_0000_0000_0000 - ((0x_0200_0000 - f) * 48_408_813)) >> 20;
let mut s = (f >> 25).wrapping_sub(32); f = poly(f & 0x_01FF_FFFF); let mut bit = (s & 1) << 37; s = ((-1 - (s as i64)) >> 1) as u64;
f |= 0x_0040_0000_0000 | bit;
bit = 1_u64 << (24 + s); if ((f & bit) != 0) && (((f & (bit - 1)) != 0) || ((f & (bit << 1)) != 0)) {
f += bit;
}
return Self::from_bits((f >> (25 + s)) as u16); }
if ui_a < 0x8000 {
Self::MAX } else if ui_a > 0x8000 {
Self::MIN_POSITIVE } else {
Self::NAR }
}
}
#[inline]
const fn poly(f: u64) -> u64 {
let mut s = (f * 7_529) >> 26;
s = (f * (20_487 + s)) >> 20;
s = (f * (0x_004F_8300 + s)) >> 24;
s = (f * (0x_038C_C980 + s)) >> 20;
s = (f * (0x_0001_EBFF_C800 + s)) >> 26;
((f * (0x_0002_C5C8_3600 + s)) >> 22) + 2048
}
#[test]
fn test_exp() {
use rand::Rng;
let mut rng = rand::thread_rng();
for _ in 0..crate::NTESTS16 {
let p_a: P16E1 = rng.gen();
let f_a = f64::from(p_a);
let p = p_a.exp();
let f = f_a.exp();
let expected = P16E1::from(f);
if expected.is_zero() || expected.is_nar() {
continue;
}
assert_eq!(p, expected);
}
}