#![no_std]
#![forbid(unsafe_code)]
#![warn(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct NegativeInput;
pub fn sqrt(x: f32) -> Result<f32, NegativeInput> {
if x.is_nan() {
return Ok(f32::NAN);
}
if x.is_infinite() {
return Ok(f32::INFINITY);
}
if x < 0.0 {
return Err(NegativeInput);
}
if x == 0.0 {
return Ok(0.0);
}
let mut r = f32::from_bits(((x.to_bits() >> 1) + 0x1FBB_4F2E) & 0x7FFF_FFFF);
for _ in 0..5 {
r = 0.5 * (r + x / r);
}
Ok(r)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn perfect_squares() {
for n in [0u32, 1, 4, 9, 16, 25, 100, 10_000] {
let expected = (n as f32).sqrt();
assert!((sqrt(n as f32).unwrap() - expected).abs() < 1e-4);
}
}
#[test]
fn irrational() {
assert!((sqrt(2.0).unwrap() - 1.414_213_5_f32).abs() < 1e-5);
}
#[test]
fn zero() {
assert_eq!(sqrt(0.0), Ok(0.0));
}
#[test]
fn negative() {
assert_eq!(sqrt(-1.0), Err(NegativeInput));
}
}