use rand::Rng; use rand::SeedableRng; use std::io::{self, Write}; const NUM_SAMPLES: usize = 10000000; fn norm_num_quaternion_f32(w: f32, x: f32, y: f32, z: f32) -> f32 { num_quaternion::Q32::new(w, x, y, z).norm() } fn norm_num_quaternion_fast_f32(w: f32, x: f32, y: f32, z: f32) -> f32 { num_quaternion::Q32::new(w, x, y, z).fast_norm() } fn norm_manual_f32(w: f32, x: f32, y: f32, z: f32) -> f32 { w.hypot(y).hypot(x.hypot(z)) } fn norm_manual_fast_f32(w: f32, x: f32, y: f32, z: f32) -> f32 { (w * w + x * x + y * y + z * z).sqrt() } fn norm_quaternion_f32(w: f32, x: f32, y: f32, z: f32) -> f32 { quaternion::len((w, [x, y, z])) } fn norm_quaternion_core_f32(w: f32, x: f32, y: f32, z: f32) -> f32 { quaternion_core::norm((w, [x, y, z])) } fn norm_nalgebra_f32(w: f32, x: f32, y: f32, z: f32) -> f32 { nalgebra::geometry::Quaternion::new(w, x, y, z).norm() } fn norm_micromath_f32(w: f32, x: f32, y: f32, z: f32) -> f32 { micromath::Quaternion::new(w, x, y, z).magnitude() } fn main() { type NormFunc = fn(f32, f32, f32, f32) -> f32; let norm_funcs: [(NormFunc, &'static str); 8] = [ (norm_num_quaternion_f32, "num_quaternion::Q32::norm"), ( norm_num_quaternion_fast_f32, "num_quaternion::Q32::fast_norm", ), (norm_manual_f32, "hypot implementation"), (norm_manual_fast_f32, "sqrt(a² + b² + c² + d²)"), (norm_quaternion_f32, "quaternion::len"), (norm_quaternion_core_f32, "quaternion_core::norm"), (norm_nalgebra_f32, "nalgebra::...::Quaternion::norm"), (norm_micromath_f32, "micromath::Quaternion::magnitude"), ]; let func_space = norm_funcs.iter().map(|(_, name)| name.len()).max().unwrap(); let col_width = 13; println!( "Benchmarking the relative accuracy of quaternion norm implementations for different scales of the" ); println!("input quaternion.\n"); println!( "{1:func_space$} | {2:^0$} | {3:^0$} | {4:^0$} | {5:^0$}", col_width, "Implementation \\ Scale", "1.0", "sqrt(MIN_POS)", "MIN_POS", "MAX / 2" ); print!( "{1:=col_width$}\x1b[0m" ); io::stdout().flush().unwrap(); } } println!("\n\nThe columns of the table determine the scale of the input quaternion."); println!("The rows of the table determine the implementation of the quaternion norm."); println!("The values in the table are the relative RMS error of the quaternion norm."); println!("\nThe column `1.0` is for quaternions with all components uniformly sampled from the range [-1.0, 1.0]."); println!("The column `sqrt(MIN_POS)` is for quaternions with all components in the range [sqrt(MIN_POS), sqrt(MIN_POS)],"); println!("where `MIN_POS` is the minimal positive normal 32-bit IEEE-754 floating point value. Similarly for `MIN_POS`"); println!("and `MAX / 2`, where `MAX` is the maximal finite `f32` value."); }