use crate::double_double::DoubleDouble;
use crate::dyadic_float::{DyadicFloat128, DyadicSign};
use crate::logs::log1p_dyadic_tables::{LOG1P_R1, LOG1P_R2, LOG1P_S2, LOG1P_S3, LOGP1_R3};
#[cold]
pub(crate) fn log1p_accurate(e_x: i32, index: usize, m_x: DoubleDouble) -> DyadicFloat128 {
const BIG_COEFFS: [DyadicFloat128; 4] = [
DyadicFloat128 {
sign: DyadicSign::Pos,
exponent: -130,
mantissa: 0xccccccd7_4818e397_7ed78465_d460315b_u128,
},
DyadicFloat128 {
sign: DyadicSign::Neg,
exponent: -129,
mantissa: 0x80000000_000478b0_c6388a23_871ce156_u128,
},
DyadicFloat128 {
sign: DyadicSign::Pos,
exponent: -129,
mantissa: 0xaaaaaaaa_aaaaaaaa_aa807bd8_67763262_u128,
},
DyadicFloat128 {
sign: DyadicSign::Neg,
exponent: -128,
mantissa: 0x80000000_00000000_00000000_00000000_u128,
},
];
const LOG_2: DyadicFloat128 = DyadicFloat128 {
sign: DyadicSign::Pos,
exponent: -128,
mantissa: 0xb172_17f7_d1cf_79ab_c9e3_b398_03f2_f6af_u128,
};
let e_x_f128 = DyadicFloat128::new_from_f64(e_x as f64);
let mut sum = LOG_2 * e_x_f128;
sum = sum + LOG1P_R1[index];
let mut v = DyadicFloat128::new_from_f64(m_x.hi) + DyadicFloat128::new_from_f64(m_x.lo);
if m_x.hi > f64::from_bits(0x3f00000000000000) || m_x.hi < f64::from_bits(0xbf00000000000000) {
let idx2: i32 = (f64::from_bits(0x40d0000000000000)
* (m_x.hi
+ (91. * f64::from_bits(0x3f10000000000000) + f64::from_bits(0x3f00000000000000))))
as i32;
sum = sum + LOG1P_R2[idx2 as usize];
let s2 = DyadicFloat128::new_from_f64(f64::from_bits(LOG1P_S2[idx2 as usize]));
v = (v + s2) + (v * s2);
}
if v.exponent > -150 {
let zv = v.fast_as_f64();
let idx3 = (f64::from_bits(0x4140000000000000)
* (zv
+ (69. * f64::from_bits(0x3ea0000000000000) + f64::from_bits(0x3e90000000000000))))
as i32;
sum = sum + LOGP1_R3[idx3 as usize];
let s3 = DyadicFloat128::new_from_f64(f64::from_bits(LOG1P_S3[idx3 as usize]));
v = (v + s3) + (v * s3);
}
let mut p = v * BIG_COEFFS[0];
p = v * (p + BIG_COEFFS[1]);
p = v * (p + BIG_COEFFS[2]);
p = v * (p + BIG_COEFFS[3]);
p = v + (v * p);
sum + p
}