fixed-sqrt 0.3.0

Square root for fixed-point numbers
Documentation
extern crate clap;
extern crate fixed;
extern crate fixed_sqrt;

use fixed::types::*;
use fixed::traits::Fixed;
use fixed_sqrt::FastSqrt;

macro_rules! show {
  ($e:expr) => { println!("{}: {:?}", stringify!($e), $e); }
}

#[allow(unused_macros)]
macro_rules! bits8 {
  ($e:expr) => { println!("{}: {:08b}", stringify!($e), $e); }
}

#[derive(Debug, Default)]
#[allow(dead_code)]
struct MaxErr <F : Fixed> {
  pub fixed   : F,
  pub sqrt    : F,
  pub exact   : f64,
  pub err_abs : f64,
  pub err_pct : f64
}

fn main() {
  use std::io::Write;
  println!("errors main...");

  let opts = clap::Command::new ("FixedSqrt Errors Example")
    .arg (clap::Arg::new ("plot-csv")
      .short ('p')
      .help ("Dump actual vs computed sqrts to CSV for plotting"))
    .get_matches();

  macro_rules! exhaustive_unsigned {
    ($unsigned:ident) => {
      println!("{}", std::iter::repeat ('~').take (80).collect::<String>());
      show!($unsigned::MIN);
      show!($unsigned::MAX);
      let mut file = if opts.contains_id ("plot-csv") {
        Some (std::fs::File::create (format!("{}.csv", stringify!($unsigned))).unwrap())
      } else {
        None
      };
      let mut avg_err_abs = 0.0;
      let mut avg_err_pct = 0.0;
      let mut max_err_abs = MaxErr::default();
      let mut max_err_pct = MaxErr::default();
      let mut i = $unsigned::from_bits (0);
      let mut count = 0;
      loop {
        count += 1;
        let fixed   = i;
        let sqrt    = fixed.fast_sqrt();
        let exact   = fixed.to_num::<f64>().sqrt();
        let err_abs = (exact - sqrt.to_num::<f64>()).abs();
        let err_pct = if exact == 0.0 {
          assert!(err_abs == 0.0);
          0.0
        } else {
          err_abs / exact
        };
        file.as_mut().map (|file|
          file.write (format!("{},{},{}\n", fixed, exact, sqrt).as_bytes()).unwrap());
        avg_err_abs += err_abs;
        avg_err_pct += err_pct;
        if err_abs > max_err_abs.err_abs {
          max_err_abs = MaxErr { fixed, sqrt, exact, err_abs, err_pct };
        }
        if err_pct > max_err_pct.err_pct {
          max_err_pct = MaxErr { fixed, sqrt, exact, err_abs, err_pct };
        }
        if i == $unsigned::MAX {
          break
        }
        i += $unsigned::from_bits (1);
      }
      show!(count);
      avg_err_abs = avg_err_abs / count as f64;
      avg_err_pct = avg_err_pct / count as f64;
      show!(max_err_abs);
      show!(max_err_pct);
      show!(avg_err_abs);
      show!(avg_err_pct);
    }
  }

  macro_rules! exhaustive_signed {
    ($signed:ident) => {
      println!("{}", std::iter::repeat ('~').take (80).collect::<String>());
      show!($signed::MIN);
      show!($signed::MAX);
      let mut file = if opts.contains_id ("plot-csv") {
        Some (std::fs::File::create (format!("{}.csv", stringify!($signed))).unwrap())
      } else {
        None
      };
      let mut avg_err_abs = 0.0;
      let mut avg_err_pct = 0.0;
      let mut max_err_abs = MaxErr::default();
      let mut max_err_pct = MaxErr::default();
      let mut i = $signed::from_bits (0);
      let mut count = 0;
      loop {
        let fixed   = i;
        count += 1;
        let sqrt    = fixed.fast_sqrt();
        let exact   = fixed.to_num::<f64>().sqrt();
        let err_abs = (exact - sqrt.to_num::<f64>()).abs();
        let err_pct = if exact == 0.0 {
          0.0
        } else {
          err_abs / exact
        };
        file.as_mut().map (|file|
          file.write (format!("{},{},{}\n", fixed, exact, sqrt).as_bytes()).unwrap());
        avg_err_abs += err_abs;
        avg_err_pct += err_pct;
        if err_abs > max_err_abs.err_abs {
          max_err_abs = MaxErr { fixed, sqrt, exact, err_abs, err_pct };
        }
        if err_pct > max_err_pct.err_pct {
          max_err_pct = MaxErr { fixed, sqrt, exact, err_abs, err_pct };
        }
        if i == $signed::MAX {
          break
        }
        i += $signed::from_bits (1);
      }
      show!(count);
      avg_err_abs = avg_err_abs / count as f64;
      avg_err_pct = avg_err_pct / count as f64;
      show!(max_err_abs);
      show!(max_err_pct);
      show!(avg_err_abs);
      show!(avg_err_pct);
    }
  }

  exhaustive_unsigned!(U8F0);
  exhaustive_unsigned!(U7F1);
  exhaustive_unsigned!(U6F2);
  exhaustive_unsigned!(U5F3);
  exhaustive_unsigned!(U4F4);
  exhaustive_unsigned!(U3F5);
  exhaustive_unsigned!(U2F6);
  exhaustive_unsigned!(U1F7);
  exhaustive_unsigned!(U0F8);

  exhaustive_signed!(I8F0);
  exhaustive_signed!(I7F1);
  exhaustive_signed!(I6F2);
  exhaustive_signed!(I5F3);
  exhaustive_signed!(I4F4);
  exhaustive_signed!(I3F5);
  exhaustive_signed!(I2F6);
  exhaustive_signed!(I1F7);
  //exhaustive_signed!(I0F8);   // unimplemented

  exhaustive_unsigned!(U16F0);
  exhaustive_unsigned!(U15F1);
  exhaustive_unsigned!(U14F2);
  exhaustive_unsigned!(U13F3);
  exhaustive_unsigned!(U12F4);
  exhaustive_unsigned!(U11F5);
  exhaustive_unsigned!(U10F6);
  exhaustive_unsigned!(U9F7);
  exhaustive_unsigned!(U8F8);
  exhaustive_unsigned!(U7F9);
  exhaustive_unsigned!(U6F10);
  exhaustive_unsigned!(U5F11);
  exhaustive_unsigned!(U4F12);
  exhaustive_unsigned!(U3F13);
  exhaustive_unsigned!(U2F14);
  exhaustive_unsigned!(U1F15);
  exhaustive_unsigned!(U0F16);

  exhaustive_signed!(I16F0);
  exhaustive_signed!(I15F1);
  exhaustive_signed!(I14F2);
  exhaustive_signed!(I13F3);
  exhaustive_signed!(I12F4);
  exhaustive_signed!(I11F5);
  exhaustive_signed!(I10F6);
  exhaustive_signed!(I9F7);
  exhaustive_signed!(I8F8);
  exhaustive_signed!(I7F9);
  exhaustive_signed!(I6F10);
  exhaustive_signed!(I5F11);
  exhaustive_signed!(I4F12);
  exhaustive_signed!(I3F13);
  exhaustive_signed!(I2F14);
  exhaustive_signed!(I1F15);
  //exhaustive_signed!(I0F16);  // unimplemented

  println!("...errors main");
}