use crate::prelude::*;
pub fn sqrt(value: &BigInt) -> BigInt {
assert!(*value >= Zero::zero(), "NEGATIVE");
if let Some(safe_value) = value.to_i64() {
return ((safe_value as f64).sqrt().floor() as i64)
.to_bigint()
.unwrap();
}
let two = 2.to_bigint().unwrap();
let one = 1.to_bigint().unwrap();
let mut z = value.clone();
let mut x = (value / &two) + &one;
while x < z {
z = x.clone();
x = ((value / &x) + &x) / &two;
}
z
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sqrt_0_1000() {
for i in 0..1000 {
let sqrt_i = sqrt(&BigInt::from(i));
assert_eq!(sqrt_i, BigInt::from((i as f64).sqrt().floor() as i64));
}
}
#[test]
fn test_sqrt_2_powers() {
for i in 0..256 {
let root = BigInt::from(2).pow(i as u32);
let root_squared = &root * &root;
assert_eq!(sqrt(&root_squared), root);
}
}
#[test]
fn test_sqrt_max_uint256() {
let max_uint256_string =
"115792089237316195423570985008687907853269984665640564039457584007913129639935";
let max_uint256 = BigInt::from_str_radix(max_uint256_string, 10).unwrap();
let expected_sqrt =
BigInt::from_str_radix("340282366920938463463374607431768211455", 10).unwrap();
assert_eq!(sqrt(&max_uint256), expected_sqrt);
}
}