use crate::int::algos::mul::mul_schoolbook::mul_schoolbook;
use crate::int::algos::support::limbs::add_assign;
use crate::int::types::compute_limbs::{ComputeLimbs, Limbs};
use crate::int::types::Int;
#[inline]
pub(crate) fn sig_len(a: &[u64]) -> usize {
let mut l = a.len();
while l > 1 && a[l - 1] == 0 {
l -= 1;
}
l
}
#[inline]
pub(crate) fn sum_sq_radicand<const N: usize>(ma: &[u64], mb: &[u64], out: &mut [u64]) -> usize
where
Limbs<N>: ComputeLimbs,
{
let la = sig_len(ma);
let lb = sig_len(mb);
mul_schoolbook(&ma[..la], &ma[..la], &mut out[..2 * la]);
let mut bsq_buf = Limbs::<N>::double_buffered_u64();
let bsq = bsq_buf.as_mut();
mul_schoolbook(&mb[..lb], &mb[..lb], &mut bsq[..2 * lb]);
let span = (2 * la).max(2 * lb) + 1;
add_assign(&mut out[..span], &bsq[..2 * lb]);
sig_len(&out[..span])
}
#[inline]
#[must_use]
pub(crate) fn sum_sq_schoolbook<const N: usize>(a: Int<N>, b: Int<N>) -> Option<Int<N>>
where
Limbs<N>: ComputeLimbs,
{
let ma = a.unsigned_abs();
let mb = b.unsigned_abs();
let mut n_buf = Limbs::<N>::double_buffered_u64();
let n = n_buf.as_mut();
let nl = sum_sq_radicand::<N>(ma.as_limbs(), mb.as_limbs(), n);
if nl > N || (nl == N && (n[N - 1] >> 63) != 0) {
return None;
}
let mut out = [0u64; N];
out.copy_from_slice(&n[..N]);
Some(Int::<N>::from_limbs(out))
}
#[cfg(test)]
mod tests {
use super::sum_sq_schoolbook;
use crate::int::types::Int;
#[test]
fn sum_sq_3_4_is_25() {
let a = Int::<2>::from_i64(3);
let b = Int::<2>::from_i64(4);
assert_eq!(sum_sq_schoolbook::<2>(a, b).unwrap().as_i128(), 25);
}
#[test]
fn sum_sq_is_sign_independent() {
let r = sum_sq_schoolbook::<2>(Int::<2>::from_i64(-3), Int::<2>::from_i64(-4));
assert_eq!(r.unwrap().as_i128(), 25);
}
#[test]
fn sum_sq_zero_zero_is_zero() {
let z = Int::<2>::from_i64(0);
assert_eq!(sum_sq_schoolbook::<2>(z, z).unwrap().as_i128(), 0);
}
#[test]
fn sum_sq_zero_x_is_x_squared() {
let z = Int::<2>::from_i64(0);
let x = Int::<2>::from_i64(123456789);
assert_eq!(
sum_sq_schoolbook::<2>(z, x).unwrap().as_i128(),
123456789i128 * 123456789
);
}
#[test]
fn sum_sq_orders_like_hypot() {
let small = sum_sq_schoolbook::<2>(Int::<2>::from_i64(3), Int::<2>::from_i64(4)).unwrap();
let large = sum_sq_schoolbook::<2>(Int::<2>::from_i64(5), Int::<2>::from_i64(12)).unwrap();
assert!(large.as_i128() > small.as_i128());
assert_eq!(small.as_i128(), 25);
assert_eq!(large.as_i128(), 169);
}
#[test]
fn sum_sq_overflow_returns_none() {
let m = Int::<2>::MAX;
assert_eq!(sum_sq_schoolbook::<2>(m, m), None);
}
}