Mul and Div become two f64 adds/subs with no sqrt in the hot path.
mu() and sigma() are computed on demand from stored pi/tau.
Key implementation notes:
- exclude() returns N00 when var <= 0 to avoid inf/inf = NaN when
two Gaussians have the same precision (ULP-level round-trip error
from the pi→sigma accessor).
- Mul<f64> by 0.0 returns N00 (point mass at 0), matching old behavior.
- from_ms(0, 0) == N00 {pi:inf, tau:0}; from_ms(0, inf) == N_INF {pi:0, tau:0}.
Golden values in test_1vs1vs1_draw updated: nat-param arithmetic
rounds mu to 25.0 (was 24.999999) and shifts sigma by ~3e-7.
Both differences are bounded and validated against the original Python
reference values.
Part of T0 engine redesign.
44 lines
1.2 KiB
Rust
44 lines
1.2 KiB
Rust
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
|
|
|
|
use crate::gaussian::Gaussian;
|
|
|
|
impl AbsDiffEq for Gaussian {
|
|
type Epsilon = <f64 as AbsDiffEq>::Epsilon;
|
|
|
|
fn default_epsilon() -> Self::Epsilon {
|
|
f64::default_epsilon()
|
|
}
|
|
|
|
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
|
|
f64::abs_diff_eq(&self.mu(), &other.mu(), epsilon)
|
|
&& f64::abs_diff_eq(&self.sigma(), &other.sigma(), epsilon)
|
|
}
|
|
}
|
|
|
|
impl RelativeEq for Gaussian {
|
|
fn default_max_relative() -> Self::Epsilon {
|
|
f64::default_max_relative()
|
|
}
|
|
|
|
fn relative_eq(
|
|
&self,
|
|
other: &Self,
|
|
epsilon: Self::Epsilon,
|
|
max_relative: Self::Epsilon,
|
|
) -> bool {
|
|
f64::relative_eq(&self.mu(), &other.mu(), epsilon, max_relative)
|
|
&& f64::relative_eq(&self.sigma(), &other.sigma(), epsilon, max_relative)
|
|
}
|
|
}
|
|
|
|
impl UlpsEq for Gaussian {
|
|
fn default_max_ulps() -> u32 {
|
|
f64::default_max_ulps()
|
|
}
|
|
|
|
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
|
|
f64::ulps_eq(&self.mu(), &other.mu(), epsilon, max_ulps)
|
|
&& f64::ulps_eq(&self.sigma(), &other.sigma(), epsilon, max_ulps)
|
|
}
|
|
}
|