const SIG_BITS: u32 = 52;
const BITS: u32 = 64;
const EXP_BITS: u32 = BITS - SIG_BITS - 1;
const EXP_SAT: u32 = (1 << EXP_BITS) - 1;
const EXP_BIAS: u32 = EXP_SAT >> 1;
const SIG_MASK: u64 = 4503599627370495;
const EXP_MAX: i32 = EXP_BIAS as i32;
const EXP_MIN: i32 = -(EXP_MAX - 1);
pub(crate) const fn scalbn(mut x: f64, mut n: i32) -> f64 {
let zero = 0;
let sig_total_bits = SIG_BITS + 1;
let exp_max = EXP_MAX;
let exp_min = EXP_MIN;
let f_exp_max = from_parts(false, EXP_BIAS << 1, zero);
let f_exp_min = from_parts(false, 1, zero);
let f_pow_subnorm = from_parts(false, sig_total_bits + EXP_BIAS, zero);
if n > exp_max {
debug_assert!(-exp_min + SIG_BITS as i32 + exp_max <= exp_max * 3);
x *= f_exp_max;
n -= exp_max;
if n > exp_max {
x *= f_exp_max;
n -= exp_max;
if n > exp_max {
n = exp_max;
}
}
} else if n < exp_min {
if BITS > 16 {
let mul = f_exp_min * f_pow_subnorm;
let add = -exp_min - sig_total_bits as i32;
debug_assert!(-exp_min + SIG_BITS as i32 + exp_max <= add * 2 + -exp_min);
x *= mul;
n += add;
if n < exp_min {
x *= mul;
n += add;
if n < exp_min {
n = exp_min;
}
}
} else {
let add = -clamp(n + sig_total_bits as i32, exp_min, sig_total_bits as i32);
let mul = from_parts(false, (EXP_BIAS as i32 - add) as u32, zero);
x *= mul;
n += add;
if n < exp_min {
let add = -clamp(n + sig_total_bits as i32, exp_min, sig_total_bits as i32);
let mul = from_parts(false, (EXP_BIAS as i32 - add) as u32, zero);
x *= mul;
n += add;
if n < exp_min {
n = exp_min;
}
}
}
}
let scale = from_parts(false, (EXP_BIAS as i32 + n) as u32, zero);
x * scale
}
const fn from_parts(negative: bool, exponent: u32, significand: i32) -> f64 {
let sign = if negative { 1_u64 } else { 0 };
f64::from_bits(
(sign << (BITS - 1))
| ((exponent as u64 & EXP_SAT as u64) << SIG_BITS)
| (significand as u64 & SIG_MASK),
)
}
const fn clamp(x: i32, min: i32, max: i32) -> i32 {
assert!(min <= max);
if x < min {
min
} else if x > max {
max
} else {
x
}
}