130 lines
3.0 KiB
Rust
130 lines
3.0 KiB
Rust
//! 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<T: DotProduct>(a: T, b: T) -> f32 {
|
|
a.dot(b)
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn dot_fast<T: DotProduct>(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<T: CrossProduct>(a: T, b: T) -> T {
|
|
a.cross(b)
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn cross_fast<T: CrossProduct>(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<T>(a: T, b: T, c: T, d: T) -> T
|
|
where
|
|
T: Copy + FMulAdd + Add<Output = T> + Mul<Output = T> + Neg<Output = T>,
|
|
{
|
|
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<T>(a: T, b: T, c: T, d: T) -> T
|
|
where
|
|
T: Copy + FMulAdd + Add<Output = T> + Mul<Output = T> + Neg<Output = T>,
|
|
{
|
|
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<T>(a: T, b: T) -> (T, T)
|
|
// (product, rounding_err)
|
|
where
|
|
T: Copy + FMulAdd + Mul<Output = T> + Neg<Output = T>,
|
|
{
|
|
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<T>(a: T, b: T) -> (T, T)
|
|
// (sum, rounding_err)
|
|
where
|
|
T: Copy + Add<Output = T> + Sub<Output = T>,
|
|
{
|
|
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<T>(a: T, b: T) -> (T, T)
|
|
// (diff, rounding_err)
|
|
where
|
|
T: Copy + Add<Output = T> + Sub<Output = T>,
|
|
{
|
|
let diff = a - b;
|
|
let delta = diff - a;
|
|
(diff, (a - (diff - delta)) - (b + delta))
|
|
}
|