From 354468ed6a07ddbf0d74cddca3d3805c9a99c6d7 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Sun, 13 Dec 2020 14:16:18 +0000 Subject: [PATCH] Use approximate assertions in value stability and increase some tolerences slightly --- rand_distr/src/cauchy.rs | 2 +- rand_distr/src/normal.rs | 3 +- rand_distr/src/pareto.rs | 16 +++++------ rand_distr/tests/value_stability.rs | 44 +++++++++++++++++++++++++---- 4 files changed, 50 insertions(+), 15 deletions(-) diff --git a/rand_distr/src/cauchy.rs b/rand_distr/src/cauchy.rs index ffe86d00a9b..1fadf0c6f61 100644 --- a/rand_distr/src/cauchy.rs +++ b/rand_distr/src/cauchy.rs @@ -160,7 +160,7 @@ mod test { let expected = [15.023088, -5.446413, 3.7092876, 3.112482]; for (a, b) in buf.iter().zip(expected.iter()) { let (a, b) = (*a, *b); - assert!((a - b).abs() < 1e-6, "expected: {} = {}", a, b); + assert!((a - b).abs() < 1e-5, "expected: {} = {}", a, b); } } } diff --git a/rand_distr/src/normal.rs b/rand_distr/src/normal.rs index ae82799147a..4ab0fbd1901 100644 --- a/rand_distr/src/normal.rs +++ b/rand_distr/src/normal.rs @@ -345,7 +345,8 @@ mod tests { assert_almost_eq!(lnorm.norm.std_dev, 1.0, 2e-16); let lnorm = LogNormal::from_mean_cv(e.powf(1.5), (e - 1.0).sqrt()).unwrap(); - assert_eq!((lnorm.norm.mean, lnorm.norm.std_dev), (1.0, 1.0)); + assert!((lnorm.norm.mean - 1.0).abs() < 1e-15); + assert_eq!(lnorm.norm.std_dev, 1.0); } #[test] fn test_log_normal_invalid_sd() { diff --git a/rand_distr/src/pareto.rs b/rand_distr/src/pareto.rs index 217899ed9a7..0c62383b1cb 100644 --- a/rand_distr/src/pareto.rs +++ b/rand_distr/src/pareto.rs @@ -87,6 +87,7 @@ where F: Float, OpenClosed01: Distribution #[cfg(test)] mod tests { use super::*; + use core::fmt::{Debug, Display}; #[test] #[should_panic] @@ -108,21 +109,20 @@ mod tests { #[test] fn value_stability() { - fn test_samples>( - distr: D, zero: F, expected: &[F], + fn test_samples>( + distr: D, thresh: F, expected: &[F], ) { let mut rng = crate::test::rng(213); - let mut buf = [zero; 4]; - for x in &mut buf { - *x = rng.sample(&distr); + for v in expected { + let x = rng.sample(&distr); + assert!((x - *v).abs() < thresh, "not approx eq: {}, {}", x, *v); } - assert_eq!(buf, expected); } - test_samples(Pareto::new(1.0, 1.0).unwrap(), 0f32, &[ + test_samples(Pareto::new(1f32, 1.0).unwrap(), 1e-6, &[ 1.0423688, 2.1235929, 4.132709, 1.4679428, ]); - test_samples(Pareto::new(2.0, 0.5).unwrap(), 0f64, &[ + test_samples(Pareto::new(2.0, 0.5).unwrap(), 1e-14, &[ 9.019295276219136, 4.3097126018270595, 6.837815045397157, diff --git a/rand_distr/tests/value_stability.rs b/rand_distr/tests/value_stability.rs index 986b9963283..aafb95552d5 100644 --- a/rand_distr/tests/value_stability.rs +++ b/rand_distr/tests/value_stability.rs @@ -6,7 +6,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::{fmt::Debug, cmp::PartialEq}; +use core::fmt::Debug; use rand::Rng; use rand_distr::*; @@ -17,12 +17,45 @@ fn get_rng(seed: u64) -> impl rand::Rng { rand_pcg::Pcg32::new(seed, INC) } -fn test_samples>( +/// We only assert approximate equality since some platforms do not perform +/// identically (i686-unknown-linux-gnu and most notably x86_64-pc-windows-gnu). +trait ApproxEq { + fn is_approx_eq(&self, rhs: &Self) -> bool; +} + +impl ApproxEq for f32 { + fn is_approx_eq(&self, rhs: &Self) -> bool { + (self - rhs).abs() < 1e-6 + } +} +impl ApproxEq for f64 { + fn is_approx_eq(&self, rhs: &Self) -> bool { + (self - rhs).abs() < 1e-14 + } +} +impl ApproxEq for u64 { + fn is_approx_eq(&self, rhs: &Self) -> bool { + self == rhs + } +} +impl ApproxEq for [T; 2] { + fn is_approx_eq(&self, rhs: &Self) -> bool { + self[0].is_approx_eq(&rhs[0]) && self[1].is_approx_eq(&rhs[1]) + } +} +impl ApproxEq for [T; 3] { + fn is_approx_eq(&self, rhs: &Self) -> bool { + self[0].is_approx_eq(&rhs[0]) && self[1].is_approx_eq(&rhs[1]) && self[2].is_approx_eq(&rhs[2]) + } +} + +fn test_samples>( seed: u64, distr: D, expected: &[F], ) { let mut rng = get_rng(seed); - for &val in expected { - assert_eq!(val, rng.sample(&distr)); + for val in expected { + let x = rng.sample(&distr); + assert!(x.is_approx_eq(&val), "not approx eq: {:?}, {:?}", x, val); } } @@ -334,11 +367,12 @@ fn cauchy_stability() { // Unfortunately this test is not fully portable due to reliance on the // system's implementation of tanf (see doc on Cauchy struct). + // We use a lower threshold of 1e-5 here. let distr = Cauchy::new(10f32, 7.0).unwrap(); let mut rng = get_rng(353); let expected = [15.023088, -5.446413, 3.7092876, 3.112482]; for &a in expected.iter() { let b = rng.sample(&distr); - assert!((a - b).abs() < 1e-6, "expected: {} = {}", a, b); + assert!((a - b).abs() < 1e-5, "not approx eq: {:?}, {:?}", a, b); } }