//! RMath: a math library for building CPU-based renderers. #![allow(dead_code)] mod normal; mod point; mod sealed; mod utils; mod vector; pub mod wide4; mod xform; use std::ops::{Add, Mul, Neg, Sub}; pub use self::{ normal::Normal, point::Point, vector::Vector, xform::AsXform, xform::Xform, xform::XformFull, }; /// Trait for calculating dot products. pub trait DotProduct { fn dot(self, other: Self) -> f32; fn dot_fast(self, other: Self) -> f32; } #[inline(always)] pub fn dot(a: T, b: T) -> f32 { a.dot(b) } #[inline(always)] pub fn dot_fast(a: T, b: T) -> f32 { a.dot_fast(b) } /// Trait for calculating cross products. pub trait CrossProduct { fn cross(self, other: Self) -> Self; fn cross_fast(self, other: Self) -> Self; } #[inline(always)] pub fn cross(a: T, b: T) -> T { a.cross(b) } #[inline(always)] pub fn cross_fast(a: T, b: T) -> T { a.cross_fast(b) } //------------------------------------------------------------- /// Trait representing types that can do fused multiply-add. trait FMulAdd { /// `(self * b) + c` with only one floating point rounding error. fn fma(self, b: Self, c: Self) -> Self; } impl FMulAdd for f32 { fn fma(self, b: Self, c: Self) -> Self { self.mul_add(b, c) } } /// `(a * b) - (c * d)` but done with high precision via floating point tricks. /// /// See https://pharr.org/matt/blog/2019/11/03/difference-of-floats #[inline(always)] fn difference_of_products(a: T, b: T, c: T, d: T) -> T where T: Copy + FMulAdd + Add + Mul + Neg, { let cd = c * d; let dop = a.fma(b, -cd); let err = (-c).fma(d, cd); dop + err } /// `(a * b) + (c * d)` but done with high precision via floating point tricks. #[inline(always)] fn sum_of_products(a: T, b: T, c: T, d: T) -> T where T: Copy + FMulAdd + Add + Mul + Neg, { let cd = c * d; let sop = a.fma(b, cd); let err = c.fma(d, -cd); sop + err } /// `a * b` but also returns a rounding error for precise composition /// with other operations. #[inline(always)] fn two_prod(a: T, b: T) -> (T, T) // (product, rounding_err) where T: Copy + FMulAdd + Mul + Neg, { let ab = a * b; (ab, a.fma(b, -ab)) } /// `a + b` but also returns a rounding error for precise composition /// with other operations. #[inline(always)] fn two_sum(a: T, b: T) -> (T, T) // (sum, rounding_err) where T: Copy + Add + Sub, { let sum = a + b; let delta = sum - a; (sum, (a - (sum - delta)) + (b - delta)) } /// `a - b` but also returns a rounding error for precise composition /// with other operations. #[inline(always)] fn two_diff(a: T, b: T) -> (T, T) // (diff, rounding_err) where T: Copy + Add + Sub, { let diff = a - b; let delta = diff - a; (diff, (a - (diff - delta)) - (b + delta)) }