use crate::int::algos::support::limbs::{cmp, sub_assign};
use crate::int::policy::mul::dispatch_slice as mul_slice;
const MAX_POW_U64: usize = 104;
const MAX_R_U64: usize = 240;
const MAX_MAG_U64: usize = 136;
const MAX_PROD_U64: usize = MAX_MAG_U64 + MAX_R_U64;
const MAX_POW_U128: usize = MAX_POW_U64.div_ceil(2);
const MAX_R_U128: usize = MAX_R_U64.div_ceil(2);
const MAX_MAG_U128: usize = MAX_MAG_U64.div_ceil(2);
const MAX_PROD_U128: usize = MAX_PROD_U64.div_ceil(2);
#[derive(Clone)]
pub struct NewtonReciprocal {
r: [u64; MAX_R_U64],
r_len: usize,
k_u64: usize,
pow_scale: [u64; MAX_POW_U64],
pow_len: usize,
r_u128: [u128; MAX_R_U128],
r_u128_len: usize,
k_u128: usize,
pow_u128: [u128; MAX_POW_U128],
pow_u128_len: usize,
}
impl NewtonReciprocal {
pub fn precompute(scale: u32, width_u64_limbs: usize) -> Self {
let width_limbs = width_u64_limbs;
let pow_len = (scale as usize / 19 + 3).max(1);
debug_assert!(pow_len <= MAX_POW_U64, "pow_scale buffer too small");
let mut pow_scale = [0u64; MAX_POW_U64];
if let Some(limbs) = crate::consts::pow10_limbs(scale) {
debug_assert!(limbs.len() <= pow_len, "pow10 table entry exceeds pow_len");
pow_scale[..limbs.len()].copy_from_slice(limbs);
} else {
pow_scale[0] = 1u64;
for _ in 0..scale {
let mut carry: u64 = 0;
for limb in pow_scale[..pow_len].iter_mut() {
let prod = (*limb as u128) * 10u128 + (carry as u128);
*limb = prod as u64;
carry = (prod >> 64) as u64;
}
debug_assert_eq!(carry, 0, "pow_scale buffer too small at scale={scale}");
}
}
let k_u64_raw = width_limbs + pow_len;
let k_u64 = if k_u64_raw.is_multiple_of(2) { k_u64_raw } else { k_u64_raw + 1 };
debug_assert!(k_u64 < MAX_R_U64, "num buffer too small");
let mut r = [0u64; MAX_R_U64];
if let Some(baked) = crate::consts::newton_recip_le(scale, width_limbs) {
debug_assert_eq!(baked.len(), k_u64 + 1, "baked newton recip length");
r[..k_u64 + 1].copy_from_slice(baked);
} else {
let mut num = [0u64; MAX_R_U64];
num[k_u64] = 1u64;
let mut rem = [0u64; MAX_POW_U64];
use crate::int::policy::div_rem::{select_for_limbs, Algorithm};
match select_for_limbs(&num[..k_u64 + 1], &pow_scale[..pow_len]) {
Algorithm::Rem => crate::int::algos::div::div_rem::div_rem(
&num[..k_u64 + 1],
&pow_scale[..pow_len],
&mut r[..k_u64 + 1],
&mut rem[..pow_len],
),
_ => {
let mut u = [0u64; MAX_R_U64 + 2];
let mut v = [0u64; MAX_POW_U64];
crate::int::algos::div::div_knuth::div_knuth_into(
&num[..k_u64 + 1],
&pow_scale[..pow_len],
&mut r[..k_u64 + 1],
&mut rem[..pow_len],
&mut u,
&mut v,
);
}
}
}
let r_len = k_u64 + 1;
let r_u128_len = r_len.div_ceil(2);
let pow_u128_len = pow_len.div_ceil(2);
let mut r_u128 = [0u128; MAX_R_U128];
let mut i = 0;
while i < r_u128_len {
let lo = r[2 * i] as u128;
let hi = r[2 * i + 1] as u128;
r_u128[i] = lo | (hi << 64);
i += 1;
}
let mut pow_u128 = [0u128; MAX_POW_U128];
let mut i = 0;
while i < pow_u128_len {
let lo = pow_scale[2 * i] as u128;
let hi = pow_scale[2 * i + 1] as u128;
pow_u128[i] = lo | (hi << 64);
i += 1;
}
let k_u128 = k_u64 / 2;
Self {
r,
r_len,
k_u64,
pow_scale,
pow_len,
r_u128,
r_u128_len,
k_u128,
pow_u128,
pow_u128_len,
}
}
}
fn div_newton(
n: &[u64],
table: &NewtonReciprocal,
quot: &mut [u64],
rem_out: &mut [u64],
) -> usize {
let r = &table.r[..table.r_len];
let pow_scale = &table.pow_scale[..table.pow_len];
let prod_len = n.len() + r.len();
debug_assert!(prod_len <= MAX_PROD_U64, "product buffer too small");
let mut prod = [0u64; MAX_PROD_U64];
mul_slice(n, r, &mut prod[..prod_len]);
let lo = table.k_u64.min(prod_len);
let q_slice = &prod[lo..prod_len];
for (dst, src) in quot.iter_mut().zip(q_slice.iter()) {
*dst = *src;
}
for dst in quot.iter_mut().skip(q_slice.len()) {
*dst = 0;
}
let prod2_len = quot.len() + pow_scale.len();
debug_assert!(prod2_len <= MAX_PROD_U64, "product buffer too small");
let mut prod2 = [0u64; MAX_PROD_U64];
mul_slice(quot, pow_scale, &mut prod2[..prod2_len]);
let rem_len = n.len() + 1;
debug_assert!(rem_len <= MAX_MAG_U64 + 1, "rem buffer too small");
for (dst, src) in rem_out.iter_mut().take(rem_len).zip(n.iter()) {
*dst = *src;
}
rem_out[rem_len - 1] = 0;
let sub_len = prod2_len.min(rem_len);
let _ = sub_assign(&mut rem_out[..sub_len], &prod2[..sub_len]);
loop {
if cmp(&rem_out[..rem_len], pow_scale) < 0 {
break;
}
let s = rem_len.min(pow_scale.len());
let _ = sub_assign(&mut rem_out[..s], &pow_scale[..s]);
let mut carry: u64 = 1;
for limb in quot.iter_mut() {
let (s, c) = limb.overflowing_add(carry);
*limb = s;
if !c {
carry = 0;
break;
}
}
let _ = carry;
}
rem_len
}
#[inline]
const fn cmp_u128(a: &[u128], b: &[u128]) -> i32 {
let mut alen = a.len();
while alen > 0 && a[alen - 1] == 0 { alen -= 1; }
let mut blen = b.len();
while blen > 0 && b[blen - 1] == 0 { blen -= 1; }
if alen != blen { return if alen > blen { 1 } else { -1 }; }
let mut i = alen;
while i > 0 {
i -= 1;
if a[i] != b[i] { return if a[i] > b[i] { 1 } else { -1 }; }
}
0
}
#[inline]
const fn sub_assign_u128(a: &mut [u128], b: &[u128]) -> bool {
let mut borrow: u128 = 0;
let mut i = 0;
while i < a.len() {
let bi = if i < b.len() { b[i] } else { 0 };
let (s1, c1) = a[i].overflowing_sub(bi);
let (s2, c2) = s1.overflowing_sub(borrow);
a[i] = s2;
borrow = (c1 as u128) | (c2 as u128);
i += 1;
}
borrow != 0
}
#[inline]
fn mul_schoolbook_u128(a: &[u128], b: &[u128], out: &mut [u128]) {
use crate::int::types::compute_limbs::Limb;
let mut i = 0;
while i < a.len() {
if a[i] != 0 {
let mut carry: u128 = 0;
let mut j = 0;
while j < b.len() {
if b[j] != 0 || carry != 0 {
let (prod_lo, prod_hi) = <u128 as Limb>::widening_mul(a[i], b[j]);
let idx = i + j;
let (s1, c1) = out[idx].overflowing_add(prod_lo);
let (s2, c2) = s1.overflowing_add(carry);
out[idx] = s2;
carry = prod_hi.wrapping_add(c1 as u128).wrapping_add(c2 as u128);
}
j += 1;
}
let mut idx = i + b.len();
while carry != 0 && idx < out.len() {
let (s, c) = out[idx].overflowing_add(carry);
out[idx] = s;
carry = c as u128;
idx += 1;
}
}
i += 1;
}
}
#[inline]
fn mul_high_schoolbook_u128(a: &[u128], b: &[u128], out: &mut [u128], base: usize) {
use crate::int::types::compute_limbs::Limb;
let out_len = out.len();
let mut i = 0;
while i < a.len() {
if a[i] != 0 {
let j0 = base.saturating_sub(i);
let mut carry: u128 = 0;
let mut j = j0;
while j < b.len() {
let (lo, hi) = <u128 as Limb>::widening_mul(a[i], b[j]);
let idx = i + j - base; let (s1, c1) = out[idx].overflowing_add(lo);
let (s2, c2) = s1.overflowing_add(carry);
out[idx] = s2;
carry = hi.wrapping_add(c1 as u128).wrapping_add(c2 as u128);
j += 1;
}
let mut idx = i + b.len() - base;
while carry != 0 && idx < out_len {
let (s, c) = out[idx].overflowing_add(carry);
out[idx] = s;
carry = c as u128;
idx += 1;
}
}
i += 1;
}
}
fn div_newton_u128(
n: &[u128],
table: &NewtonReciprocal,
quot: &mut [u128],
rem_out: &mut [u128],
) -> usize {
let r = &table.r_u128[..table.r_u128_len];
let pow_scale = &table.pow_u128[..table.pow_u128_len];
let prod_len = n.len() + r.len();
let lo = table.k_u128.min(prod_len);
const GUARD: usize = 2;
let base = lo.saturating_sub(GUARD);
let high_len = prod_len - base;
debug_assert!(high_len <= MAX_PROD_U128, "u128 high-product buffer too small");
let mut prod = [0u128; MAX_PROD_U128];
mul_high_schoolbook_u128(n, r, &mut prod[..high_len], base);
let q_slice = &prod[lo - base..high_len];
for (dst, src_) in quot.iter_mut().zip(q_slice.iter()) { *dst = *src_; }
for dst in quot.iter_mut().skip(q_slice.len()) { *dst = 0; }
let prod2_len = quot.len() + pow_scale.len();
debug_assert!(prod2_len <= MAX_PROD_U128, "u128 product buffer too small");
let mut prod2 = [0u128; MAX_PROD_U128];
mul_schoolbook_u128(quot, pow_scale, &mut prod2[..prod2_len]);
let rem_len = n.len() + 1;
debug_assert!(rem_len <= MAX_MAG_U128 + 1, "u128 rem buffer too small");
for (dst, src_) in rem_out.iter_mut().take(rem_len).zip(n.iter()) { *dst = *src_; }
rem_out[rem_len - 1] = 0;
let sub_len = prod2_len.min(rem_len);
let _ = sub_assign_u128(&mut rem_out[..sub_len], &prod2[..sub_len]);
loop {
if cmp_u128(&rem_out[..rem_len], pow_scale) < 0 { break; }
let s = rem_len.min(pow_scale.len());
let _ = sub_assign_u128(&mut rem_out[..s], &pow_scale[..s]);
let mut carry: u128 = 1;
for limb in quot.iter_mut() {
let (s, c) = limb.overflowing_add(carry);
*limb = s;
if !c { carry = 0; break; }
}
let _ = carry;
}
rem_len
}
pub(crate) fn newton_pow10_mag_u128_packed(
mag_u128: &mut [u128],
neg: bool,
mode: crate::support::rounding::RoundingMode,
table: &NewtonReciprocal,
) {
use crate::support::rounding;
let mag_len = mag_u128.len();
let mut top = mag_len;
while top > 0 && mag_u128[top - 1] == 0 { top -= 1; }
let n_slice = &mag_u128[..top.max(1)];
let mut quot = [0u128; MAX_MAG_U128];
let mut rem = [0u128; MAX_MAG_U128 + 1];
let rem_len = div_newton_u128(n_slice, table, &mut quot[..mag_len], &mut rem);
let rem_is_zero = rem[..rem_len].iter().all(|&x| x == 0);
if !rem_is_zero {
let pow_len = table.pow_u128_len;
let mut half = [0u128; MAX_POW_U128];
half[..pow_len].copy_from_slice(&table.pow_u128[..pow_len]);
let mut i = pow_len;
let mut carry_in: u128 = 0;
while i > 0 {
i -= 1;
let next_carry = half[i] & 1;
half[i] = (carry_in << 127) | (half[i] >> 1);
carry_in = next_carry;
}
let cmp_r = match cmp_u128(&rem[..rem_len], &half[..pow_len]) {
n if n < 0 => core::cmp::Ordering::Less,
0 => core::cmp::Ordering::Equal,
_ => core::cmp::Ordering::Greater,
};
let q_is_odd = (quot[0] & 1) != 0;
if rounding::should_bump(mode, cmp_r, q_is_odd, !neg) {
let mut carry: u128 = 1;
for limb in quot[..mag_len].iter_mut() {
let (s, c) = limb.overflowing_add(carry);
*limb = s;
if !c { carry = 0; break; }
}
let _ = carry;
}
}
for (i, slot) in mag_u128.iter_mut().enumerate() { *slot = quot[i]; }
}
#[inline]
const fn newton_u128_wins(width_bits: u32) -> bool {
width_bits.is_multiple_of(128) && width_bits >= 1536 && width_bits <= 8192
}
pub(crate) fn div_wide_pow10_newton_with<W: crate::int::types::traits::BigInt>(
n: W,
scale: u32,
mode: crate::support::rounding::RoundingMode,
table: &NewtonReciprocal,
) -> W {
let mut mag_u128 = crate::int::types::compute_limbs::max_u128_limb();
let limbs = <W as crate::int::types::traits::BigInt>::U128_LIMBS;
let mag = &mut mag_u128[..limbs];
let neg = n.mag_into_u128(mag);
newton_pow10_mag_u128(mag, neg, mode, table);
W::from_mag_sign_u128(mag, neg)
}
pub(crate) fn newton_pow10_mag_u128(
mag_u128: &mut [u128],
neg: bool,
mode: crate::support::rounding::RoundingMode,
table: &NewtonReciprocal,
) {
use crate::support::rounding;
let mut mag = [0u64; MAX_MAG_U64];
for (i, &v) in mag_u128.iter().enumerate() {
mag[2 * i] = v as u64;
mag[2 * i + 1] = (v >> 64) as u64;
}
let mag_len = mag_u128.len() * 2;
let mut top = mag_len;
while top > 0 && mag[top - 1] == 0 {
top -= 1;
}
let n_slice = &mag[..top.max(1)];
let mut quot = [0u64; MAX_MAG_U64];
let mut rem = [0u64; MAX_MAG_U64 + 1];
let rem_len = div_newton(n_slice, table, &mut quot[..mag_len], &mut rem);
let rem_is_zero = rem[..rem_len].iter().all(|&x| x == 0);
if !rem_is_zero {
let pow_len = table.pow_len;
let mut half = [0u64; MAX_POW_U64];
half[..pow_len].copy_from_slice(&table.pow_scale[..pow_len]);
let mut i = pow_len;
let mut carry_in: u64 = 0;
while i > 0 {
i -= 1;
let next_carry = half[i] & 1;
half[i] = (carry_in << 63) | (half[i] >> 1);
carry_in = next_carry;
}
let cmp_r = match cmp(&rem[..rem_len], &half[..pow_len]) {
n if n < 0 => core::cmp::Ordering::Less,
0 => core::cmp::Ordering::Equal,
_ => core::cmp::Ordering::Greater,
};
let q_is_odd = (quot[0] & 1) != 0;
if rounding::should_bump(mode, cmp_r, q_is_odd, !neg) {
let mut carry: u64 = 1;
for limb in quot[..mag_len].iter_mut() {
let (s, c) = limb.overflowing_add(carry);
*limb = s;
if !c {
carry = 0;
break;
}
}
let _ = carry;
}
}
for (i, slot) in mag_u128.iter_mut().enumerate() {
let lo = quot[2 * i] as u128;
let hi = quot[2 * i + 1] as u128;
*slot = lo | (hi << 64);
}
}
#[inline]
pub(crate) fn newton_rescale_arm(
mag: &mut [u128],
scale: u32,
neg: bool,
mode: crate::support::rounding::RoundingMode,
width_bits: u32,
) {
#[cfg(feature = "std")]
{
let width_limbs = (width_bits as usize) / 64;
let table = NewtonReciprocal::precompute(scale, width_limbs);
if newton_u128_wins(width_bits) {
newton_pow10_mag_u128_packed(mag, neg, mode, &table);
} else {
newton_pow10_mag_u128(mag, neg, mode, &table);
}
}
#[cfg(not(feature = "std"))]
{
let _ = width_bits;
crate::algos::support::mg_divide::div_pow10_chain_mag_u128(mag, scale, neg, mode);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(any(
feature = "d307",
feature = "d462",
feature = "d616",
feature = "d924",
feature = "d1232"
))]
use crate::algos::support::mg_divide::div_wide_pow10_chain;
#[cfg(any(
feature = "d307",
feature = "d462",
feature = "d616",
feature = "d924",
feature = "d1232"
))]
use crate::int::types::Int;
use crate::support::rounding::RoundingMode;
#[cfg(feature = "xx-wide")]
#[test]
fn baked_newton_recip_matches_runtime_divide() {
use crate::int::algos::div::div_fixed::div_rem_mag_slice;
for &width_limbs in &[16usize, 24, 32, 48, 64, 96, 128, 132] {
for &scale in &[1u32, 38, 39, 77, 200, 461, 615, 924, 1231, 1850] {
let pow_len = (scale as usize / 19 + 3).max(1);
let mut pow = [0u64; MAX_POW_U64];
pow[0] = 1;
for _ in 0..scale {
let mut carry = 0u64;
for limb in pow[..pow_len].iter_mut() {
let p = (*limb as u128) * 10 + carry as u128;
*limb = p as u64;
carry = (p >> 64) as u64;
}
assert_eq!(carry, 0, "10^{scale} overflowed pow_len");
}
let k_raw = width_limbs + pow_len;
let k = if k_raw % 2 == 0 { k_raw } else { k_raw + 1 };
let mut num = [0u64; MAX_R_U64];
num[k] = 1;
let mut r = [0u64; MAX_R_U64];
let mut rem = [0u64; MAX_POW_U64];
div_rem_mag_slice(&num[..k + 1], &pow[..pow_len], &mut r[..k + 1], &mut rem[..pow_len]);
let baked = crate::consts::newton_recip_le(scale, width_limbs)
.expect("baked reciprocal in range");
assert_eq!(
baked,
&r[..k + 1],
"baked != runtime divide: width_limbs={width_limbs} scale={scale}"
);
}
}
}
#[cfg(feature = "d307")]
#[test]
fn newton_matches_mg_chain_d307_s150() {
let scale = 150u32;
let width_limbs = 16; let table = NewtonReciprocal::precompute(scale, width_limbs);
let mut limbs = [0u128; 64];
limbs[6] = 1u128 << 32;
limbs[0] = 42;
let n = <Int<16> as crate::int::types::traits::BigInt>::from_mag_sign_u128(&limbs, false);
let got = div_wide_pow10_newton_with(n, scale, RoundingMode::HalfToEven, &table);
let want = div_wide_pow10_chain::<Int<16>>(n, scale, RoundingMode::HalfToEven);
assert_eq!(got, want, "Newton differs from MG chain at D307 s=150");
}
#[cfg(feature = "d462")]
#[test]
fn newton_matches_mg_chain_d462_s202() {
let scale = 202u32;
let width_limbs = 24; let table = NewtonReciprocal::precompute(scale, width_limbs);
let mut limbs = [0u128; 64];
limbs[10] = 1u128 << 24;
limbs[2] = 0xfeedfacecafef00d_u128;
let n = <Int<24> as crate::int::types::traits::BigInt>::from_mag_sign_u128(&limbs, false);
let got = div_wide_pow10_newton_with(n, scale, RoundingMode::HalfToEven, &table);
let want = div_wide_pow10_chain::<Int<24>>(n, scale, RoundingMode::HalfToEven);
assert_eq!(got, want, "Newton differs from MG chain at Int<24> s=202");
}
#[cfg(feature = "d462")]
#[test]
fn newton_matches_mg_chain_d462_s259() {
let scale = 259u32;
let width_limbs = 24;
let table = NewtonReciprocal::precompute(scale, width_limbs);
let mut limbs = [0u128; 64];
limbs[10] = 1u128 << 8;
limbs[1] = 0xdeadbeef_cafef00d_u128;
let n = <Int<24> as crate::int::types::traits::BigInt>::from_mag_sign_u128(&limbs, false);
let got = div_wide_pow10_newton_with(n, scale, RoundingMode::HalfToEven, &table);
let want = div_wide_pow10_chain::<Int<24>>(n, scale, RoundingMode::HalfToEven);
assert_eq!(got, want, "Newton differs from MG chain at Int<24> s=259");
}
#[cfg(feature = "d616")]
#[test]
fn newton_matches_mg_chain_d616_s308() {
let scale = 308u32;
let width_limbs = 32; let table = NewtonReciprocal::precompute(scale, width_limbs);
let mut limbs = [0u128; 64];
limbs[14] = 1u128 << 16;
limbs[3] = 0xdeadbeef;
let n = <Int<32> as crate::int::types::traits::BigInt>::from_mag_sign_u128(&limbs, false);
let got = div_wide_pow10_newton_with(n, scale, RoundingMode::HalfToEven, &table);
let want = div_wide_pow10_chain::<Int<32>>(n, scale, RoundingMode::HalfToEven);
assert_eq!(got, want, "Newton differs from MG chain at D616 s=308");
}
#[cfg(feature = "d1232")]
#[test]
fn newton_matches_mg_chain_d1232_s615() {
let scale = 615u32;
let width_limbs = 64; let table = NewtonReciprocal::precompute(scale, width_limbs);
let mut limbs = [0u128; 64];
limbs[30] = 1u128 << 8;
limbs[5] = 0xcafef00d;
let n = <Int<64> as crate::int::types::traits::BigInt>::from_mag_sign_u128(&limbs, false);
let got = div_wide_pow10_newton_with(n, scale, RoundingMode::HalfToEven, &table);
let want = div_wide_pow10_chain::<Int<64>>(n, scale, RoundingMode::HalfToEven);
assert_eq!(got, want, "Newton differs from MG chain at D1232 s=615");
}
fn assert_u64_u128_match(
scale: u32,
width_limbs: usize,
mag_limbs: usize,
top_limb_idx: usize,
top_limb_val: u128,
low_perturbation: (usize, u128),
) {
let table = NewtonReciprocal::precompute(scale, width_limbs);
let modes = [
RoundingMode::HalfToEven,
RoundingMode::HalfAwayFromZero,
RoundingMode::HalfTowardZero,
RoundingMode::Trunc,
RoundingMode::Floor,
RoundingMode::Ceiling,
];
for mode in modes {
let mut mag_a = [0u128; 128];
mag_a[top_limb_idx] = top_limb_val;
mag_a[low_perturbation.0] = low_perturbation.1;
let mut mag_b = mag_a;
super::newton_pow10_mag_u128(&mut mag_a[..mag_limbs], false, mode, &table);
super::newton_pow10_mag_u128_packed(&mut mag_b[..mag_limbs], false, mode, &table);
assert_eq!(
mag_a, mag_b,
"u64 != u128 Newton at scale={scale} width={width_limbs} mode={mode:?}"
);
let mut mag_a = [0u128; 128];
mag_a[top_limb_idx] = top_limb_val;
mag_a[low_perturbation.0] = low_perturbation.1;
let mut mag_b = mag_a;
super::newton_pow10_mag_u128(&mut mag_a[..mag_limbs], true, mode, &table);
super::newton_pow10_mag_u128_packed(&mut mag_b[..mag_limbs], true, mode, &table);
assert_eq!(
mag_a, mag_b,
"u64 != u128 Newton (neg) at scale={scale} width={width_limbs} mode={mode:?}"
);
}
}
#[cfg(feature = "d307")]
#[test]
fn newton_u64_eq_u128_d307_s150() {
assert_u64_u128_match(150, 16, 8, 6, 1u128 << 32, (1, 0xdeadbeef_cafef00d_u128));
}
#[cfg(feature = "d307")]
#[test]
fn newton_u64_eq_u128_d307_s307() {
assert_u64_u128_match(307, 16, 8, 7, 0x1234_5678_9abc_def0u128, (0, 1));
}
#[cfg(feature = "d462")]
#[test]
fn newton_u64_eq_u128_b1536_s200() {
assert_u64_u128_match(200, 24, 12, 10, 1u128 << 24, (2, 0xfeedfacecafef00d_u128));
}
#[cfg(feature = "d462")]
#[test]
fn newton_u64_eq_u128_b1536_s202() {
assert_u64_u128_match(202, 24, 12, 10, 1u128 << 24, (2, 0xfeedfacecafef00d_u128));
}
#[cfg(feature = "d462")]
#[test]
fn newton_u64_eq_u128_b1536_s259() {
assert_u64_u128_match(259, 24, 12, 10, 1u128 << 8, (1, 0xdeadbeef_cafef00d_u128));
}
#[cfg(feature = "d462")]
#[test]
fn newton_u64_eq_u128_b1536_s461() {
assert_u64_u128_match(461, 24, 12, 11, 0x1u128, (3, 0xfacefacef00d_u128));
}
#[cfg(feature = "d616")]
#[test]
fn newton_u64_eq_u128_d616_s308() {
assert_u64_u128_match(308, 32, 16, 14, 1u128 << 16, (3, 0xdeadbeef));
}
#[cfg(feature = "d616")]
#[test]
fn newton_u64_eq_u128_d616_s616() {
assert_u64_u128_match(616, 32, 16, 15, 1u128 << 8, (4, 0xfeedface));
}
#[cfg(feature = "d924")]
#[test]
fn newton_u64_eq_u128_d924_s460() {
assert_u64_u128_match(460, 48, 24, 22, 1u128 << 8, (5, 0xcafef00d));
}
#[cfg(feature = "d924")]
#[test]
fn newton_u64_eq_u128_d924_s924() {
assert_u64_u128_match(924, 48, 24, 23, 1u128, (6, 0xfeedfacef00d));
}
#[cfg(feature = "d1232")]
#[test]
fn newton_u64_eq_u128_d1232_s615() {
assert_u64_u128_match(615, 64, 32, 30, 1u128 << 8, (5, 0xcafef00d));
}
#[cfg(feature = "d1232")]
#[test]
fn newton_u64_eq_u128_d1232_s1231() {
assert_u64_u128_match(1231, 64, 32, 31, 1u128, (7, 0xdeadbeef_feedface_u128));
}
#[cfg(any(feature = "d924", feature = "xx-wide"))]
#[test]
fn newton_matches_mg_chain_b6144_s200() {
let scale = 200u32;
let width_limbs = 96; let table = NewtonReciprocal::precompute(scale, width_limbs);
let mut limbs = [0u128; 64];
limbs[40] = 1u128 << 24;
limbs[3] = 0xfeedfacecafef00d_u128;
let n = <Int<96> as crate::int::types::traits::BigInt>::from_mag_sign_u128(&limbs, false);
let got = div_wide_pow10_newton_with(n, scale, RoundingMode::HalfToEven, &table);
let want = div_wide_pow10_chain::<Int<96>>(n, scale, RoundingMode::HalfToEven);
assert_eq!(got, want, "Newton differs from MG chain at Int<96> s=200");
}
#[cfg(any(feature = "d924", feature = "xx-wide"))]
#[test]
fn newton_matches_mg_chain_b6144_s953() {
let scale = 953u32;
let width_limbs = 96;
let table = NewtonReciprocal::precompute(scale, width_limbs);
let mut limbs = [0u128; 64];
limbs[46] = 1u128 << 8;
limbs[1] = 0xdeadbeef_cafef00d_u128;
let n = <Int<96> as crate::int::types::traits::BigInt>::from_mag_sign_u128(&limbs, false);
let got = div_wide_pow10_newton_with(n, scale, RoundingMode::HalfToEven, &table);
let want = div_wide_pow10_chain::<Int<96>>(n, scale, RoundingMode::HalfToEven);
assert_eq!(got, want, "Newton differs from MG chain at Int<96> s=953");
}
#[cfg(any(feature = "d924", feature = "xx-wide"))]
#[test]
fn newton_u64_eq_u128_b6144_s200() {
assert_u64_u128_match(200, 96, 48, 40, 1u128 << 24, (3, 0xfeedfacecafef00d_u128));
}
#[cfg(any(feature = "d924", feature = "xx-wide"))]
#[test]
fn newton_u64_eq_u128_b6144_s953() {
assert_u64_u128_match(953, 96, 48, 46, 1u128 << 8, (1, 0xdeadbeef_cafef00d_u128));
}
#[cfg(any(feature = "d924", feature = "xx-wide"))]
#[test]
fn newton_u64_eq_u128_b6144_s1234() {
assert_u64_u128_match(1234, 96, 48, 46, 1u128 << 16, (2, 0xcafef00dbeef_u128));
}
#[cfg(any(feature = "d924", feature = "xx-wide"))]
#[test]
fn newton_u64_eq_u128_b6144_s1850() {
assert_u64_u128_match(1850, 96, 48, 47, 1u128, (5, 0xfacefacef00d_u128));
}
}