New test program without itertools:
use std::{cmp::Ordering, fmt::Debug};
// --------------------------------------------------------------------------
// Utility functions
// --------------------------------------------------------------------------
fn assert_arrays_equal<T: FloatType>(array_a: &[FloatOrd<T>], array_b: &[T]) {
assert_eq!(array_a.len(), array_b.len());
for (a, b) in array_a.iter().map(|val| val.into_inner()).zip(array_b.iter().copied()) {
/*if !(a == b) {
println!("{:.16} != {:.16}", a, b);
println!("{:08X} != {:08X}", a.to_bits(), b.to_bits());
panic!("Did *not* match!");
}*/
assert_eq!(a, b);
}
}
// --------------------------------------------------------------------------
// Generic float type
// --------------------------------------------------------------------------
pub trait FloatType: Copy + Clone + PartialEq + PartialOrd + Default + Debug {
fn is_nan(self) -> bool;
}
impl FloatType for f32 {
#[inline]
fn is_nan(self) -> bool {
f32::is_nan(self)
}
}
impl FloatType for f64 {
#[inline]
fn is_nan(self) -> bool {
f64::is_nan(self)
}
}
// --------------------------------------------------------------------------
// Ordered wrapper
// --------------------------------------------------------------------------
#[derive(Debug, Clone, Copy)]
pub struct FloatOrd<T: FloatType>(T);
impl<T: FloatType> FloatOrd<T> {
#[inline]
pub fn new(value: T) -> Result<Self, ()> {
if value.is_nan() {
return Err(());
}
Ok(Self(value))
}
#[inline]
pub fn into_inner(self) -> T {
self.0
}
}
impl<T: FloatType> PartialEq for FloatOrd<T> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<T: FloatType> Eq for FloatOrd<T> {}
impl<T: FloatType> PartialOrd for FloatOrd<T> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<T: FloatType> Ord for FloatOrd<T> {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
if self.0 < other.0 {
Ordering::Less
} else if self.0 > other.0 {
Ordering::Greater
} else {
Ordering::Equal
}
}
}
// --------------------------------------------------------------------------
// Tests
// --------------------------------------------------------------------------
#[test]
fn test_float_1a() {
static VALUES: [f32; 11usize] = [
f32::NEG_INFINITY,
f32::MIN,
-16777215.0f32,
-1.0f32,
-f32::MIN_POSITIVE,
0.0f32,
f32::MIN_POSITIVE,
1.0f32,
16777215.0f32,
f32::MAX,
f32::INFINITY,
];
let ordered: Vec<FloatOrd<f32>> = VALUES.iter().copied().map(|val| FloatOrd::new(val).unwrap()).collect();
let n = ordered.len();
for i in 0..999999999usize {
let mut array = ordered.clone();
array.rotate_left(i % n);
array.sort();
assert_arrays_equal(&array[..], &VALUES[..]);
}
}
#[test]
fn test_float_1b() {
static VALUES: [f64; 11usize] = [
f64::NEG_INFINITY,
f64::MIN,
-9007199254740991.0f64,
-1.0f64,
-f64::MIN_POSITIVE,
0.0f64,
f64::MIN_POSITIVE,
1.0f64,
9007199254740991.0f64,
f64::MAX,
f64::INFINITY,
];
let ordered: Vec<FloatOrd<f64>> = VALUES.iter().copied().map(|val| FloatOrd::new(val).unwrap()).collect();
let n = ordered.len();
for i in 0..999999999usize {
let mut array = ordered.clone();
array.rotate_left(i % n);
array.sort();
assert_arrays_equal(&array[..], &VALUES[..]);
}
}
#[test]
fn test_float_2a() {
static VALUES: [f32; 11usize] = [
f32::MIN,
-16777215.0f32,
-1.0f32,
-f32::EPSILON,
-f32::MIN_POSITIVE / 2.0f32,
0.0f32,
f32::MIN_POSITIVE / 2.0f32,
f32::EPSILON,
1.0f32,
16777215.0f32,
f32::MAX,
];
let ordered: Vec<FloatOrd<f32>> = VALUES.iter().copied().map(|val| FloatOrd::new(val).unwrap()).collect();
let n = ordered.len();
for i in 0..999999999usize {
let mut array = ordered.clone();
array.rotate_left(i % n);
array.sort();
assert_arrays_equal(&array[..], &VALUES[..]);
}
}
#[test]
fn test_float_2b() {
static VALUES: [f64; 11usize] = [
f64::MIN,
-9007199254740991.0f64,
-1.0f64,
-f64::EPSILON,
-f64::MIN_POSITIVE / 2.0f64,
0.0f64,
f64::MIN_POSITIVE / 2.0f64,
f64::EPSILON,
1.0f64,
9007199254740991.0f64,
f64::MAX,
];
let ordered: Vec<FloatOrd<f64>> = VALUES.iter().copied().map(|val| FloatOrd::new(val).unwrap()).collect();
let n = ordered.len();
for i in 0..999999999usize {
let mut array = ordered.clone();
array.rotate_left(i % n);
array.sort();
assert_arrays_equal(&array[..], &VALUES[..]);
}
}
Result on MacOS runner:
running 4 tests
test test_float_1a ... FAILED
test test_float_2a ... FAILED
test test_float_1b ... ok
test test_float_2b ... ok
failures:
---- test_float_1a stdout ----
thread 'test_float_1a' panicked at tests/float_test.rs:15:9:
assertion `left == right` failed
left: -3.4028235e38
right: -3.4028235e38
stack backtrace:
0: __rustc::rust_begin_unwind
error: test failed, to rerun pass `--test float_test`
1: core::panicking::panic_fmt
2: core::panicking::assert_failed_inner
3: core::panicking::assert_failed
4: core::ops::function::FnOnce::call_once
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
---- test_float_2a stdout ----
thread 'test_float_2a' panicked at tests/float_test.rs:15:9:
assertion `left == right` failed
left: -5.877472e-39
right: -5.877472e-39
stack backtrace:
0: __rustc::rust_begin_unwind
1: core::panicking::panic_fmt
2: core::panicking::assert_failed_inner
3: core::panicking::assert_failed
4: core::ops::function::FnOnce::call_once
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
failures:
test_float_1a
test_float_2a
test result: FAILED. 2 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in 17.67s
Error: Process completed with exit code 101.
Attempt #2:
running 4 tests
test test_float_2a ... FAILED
test test_float_1a ... ok
test test_float_1b ... ok
test test_float_2b ... ok
failures:
---- test_float_2a stdout ----
thread 'test_float_2a' panicked at tests/float_test.rs:15:9:
assertion `left == right` failed
left: -16777215.0
right: -16777215.0
stack backtrace:
0: __rustc::rust_begin_unwind
1: core::panicking::panic_fmt
2: core::panicking::assert_failed_inner
3: core::panicking::assert_failed
4: core::ops::function::FnOnce::call_once
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
failures:
test_float_2a
test result: FAILED. 3 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 20.43s
error: test failed, to rerun pass `--test float_test`
Error: Process completed with exit code 101.
Kind of inconsistent 
Needless to say, Linux and Windows runners finish without problem.