pub fn qr_isqrt(mut val: u32) -> u32 {
let mut g = 0u32;
let mut b = 0x8000u32;
for bshift in (0..16).rev() {
let t = ((g << 1) + b) << bshift;
if t <= val {
g += b;
val -= t;
}
b >>= 1;
}
g
}
pub fn qr_ihypot(x_arg: i32, y_arg: i32) -> u32 {
let mut x = x_arg.unsigned_abs();
let x_signed = x_arg.abs();
let mut y = y_arg.unsigned_abs();
let mut y_signed = y_arg.abs();
let mask = -((x > y) as i32) & (x_signed ^ y_signed);
x ^= mask as u32;
y ^= mask as u32;
y_signed ^= mask;
let shift = (31 - qr_ilog(y)).max(0);
x = (((x as u64) << shift).wrapping_mul(0x9B74EDAA) >> 32) as u32;
y_signed = (((y_signed as i64) << shift).wrapping_mul(0x9B74EDA9) >> 32) as i32;
let mut u = x as i32;
let mut mask = -((y_signed < 0) as i32);
x = x.wrapping_add(((y_signed.wrapping_add(mask)) ^ mask) as u32);
y_signed = y_signed.wrapping_sub((u.wrapping_add(mask)) ^ mask);
u = ((x.wrapping_add(1)) >> 1) as i32;
let mut v = y_signed.wrapping_add(1) >> 1;
mask = -((y_signed < 0) as i32);
x = x.wrapping_add((v.wrapping_add(mask) ^ mask) as u32);
y_signed = y_signed.wrapping_sub((u.wrapping_add(mask)) ^ mask);
for i in 1..16 {
u = ((x.wrapping_add(1)) >> 2) as i32;
let r = (1i32 << (2 * i)) >> 1;
v = y_signed.wrapping_add(r) >> (2 * i);
mask = -((y_signed < 0) as i32);
x = x.wrapping_add((v.wrapping_add(mask) ^ mask) as u32);
y_signed = (y_signed.wrapping_sub((u.wrapping_add(mask)) ^ mask)) << 1;
}
(x + ((1u32 << shift) >> 1)) >> shift
}
pub fn qr_ilog(mut v: u32) -> i32 {
let m = (((v & 0xFFFF0000) != 0) as i32) << 4;
v >>= m;
let mut ret = m;
let m = (((v & 0xFF00) != 0) as i32) << 3;
v >>= m;
ret |= m;
let m = (((v & 0xF0) != 0) as i32) << 2;
v >>= m;
ret |= m;
let m = (((v & 0xC) != 0) as i32) << 1;
v >>= m;
ret |= m;
ret |= ((v & 0x2) != 0) as i32;
ret + (v != 0) as i32
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_qr_isqrt_basic() {
assert_eq!(qr_isqrt(0), 0);
assert_eq!(qr_isqrt(1), 1);
assert_eq!(qr_isqrt(2), 1);
assert_eq!(qr_isqrt(3), 1);
assert_eq!(qr_isqrt(4), 2);
assert_eq!(qr_isqrt(9), 3);
assert_eq!(qr_isqrt(16), 4);
assert_eq!(qr_isqrt(25), 5);
assert_eq!(qr_isqrt(100), 10);
assert_eq!(qr_isqrt(255), 15);
assert_eq!(qr_isqrt(256), 16);
}
#[test]
fn test_qr_isqrt_large() {
assert_eq!(qr_isqrt(65535), 255);
assert_eq!(qr_isqrt(65536), 256);
assert_eq!(qr_isqrt(1000000), 1000);
assert_eq!(qr_isqrt(4294967295), 65535); }
#[test]
fn test_qr_ihypot_basic() {
assert_eq!(qr_ihypot(3, 4), 5);
assert_eq!(qr_ihypot(4, 3), 5);
assert_eq!(qr_ihypot(-3, 4), 5);
assert_eq!(qr_ihypot(3, -4), 5);
assert_eq!(qr_ihypot(-3, -4), 5);
}
#[test]
fn test_qr_ihypot_pythagorean_triples() {
assert_eq!(qr_ihypot(5, 12), 13);
assert_eq!(qr_ihypot(8, 15), 17);
assert_eq!(qr_ihypot(7, 24), 25);
assert_eq!(qr_ihypot(20, 21), 29);
}
#[test]
fn test_qr_ihypot_edge_cases() {
assert_eq!(qr_ihypot(0, 0), 0);
assert_eq!(qr_ihypot(10, 0), 10);
assert_eq!(qr_ihypot(0, 10), 10);
assert_eq!(qr_ihypot(-10, 0), 10);
assert_eq!(qr_ihypot(0, -10), 10);
}
#[test]
fn test_qr_ihypot_known_error_case() {
let result = qr_ihypot(48140, 63018);
let expected = ((48140f64.powi(2) + 63018f64.powi(2)).sqrt()).round() as u32;
assert!((result as i32 - expected as i32).abs() <= 1);
}
#[test]
fn test_qr_ilog_basic() {
assert_eq!(qr_ilog(0), 0);
assert_eq!(qr_ilog(1), 1); assert_eq!(qr_ilog(2), 2); assert_eq!(qr_ilog(3), 2); assert_eq!(qr_ilog(4), 3); assert_eq!(qr_ilog(7), 3); assert_eq!(qr_ilog(8), 4); assert_eq!(qr_ilog(15), 4); assert_eq!(qr_ilog(16), 5); }
#[test]
fn test_qr_ilog_powers_of_two() {
for i in 0..31 {
let val = 1u32 << i;
assert_eq!(qr_ilog(val), i + 1);
if i > 0 {
assert_eq!(qr_ilog(val - 1), i);
}
}
}
#[test]
fn test_qr_ilog_large() {
assert_eq!(qr_ilog(255), 8); assert_eq!(qr_ilog(256), 9); assert_eq!(qr_ilog(65535), 16); assert_eq!(qr_ilog(65536), 17); assert_eq!(qr_ilog(0x7FFFFFFF), 31); assert_eq!(qr_ilog(0x80000000), 32); assert_eq!(qr_ilog(0xFFFFFFFF), 32); }
#[test]
fn test_math_functions() {
assert_eq!(qr_isqrt(100), 10);
assert_eq!(qr_ihypot(3, 4), 5);
assert_eq!(qr_ilog(256), 9);
}
}