use num;
pub fn copysign<T>(f1: T, f2: T) -> T
where
T: num::Float,
{
if f1.is_sign_positive() && f2.is_sign_positive()
|| f1.is_sign_negative() && f2.is_sign_negative()
{
f1
} else {
f1.neg()
}
}
pub fn truncate_to_int<From, To>(f1: From) -> To
where
From: num::Float,
To: num::NumCast,
{
To::from(f1.trunc()).unwrap()
}
pub fn round_to_int<From, To>(f1: From) -> To
where
From: num::Float,
To: num::NumCast,
{
To::from(f1.round()).unwrap()
}
pub fn u32_to_f32(i: u32) -> f32 {
f32::from_bits(i)
}
pub fn u64_to_f64(i: u64) -> f64 {
f64::from_bits(i)
}
pub fn f32_is_signaling_nan(f: f32) -> bool {
let uf: u32 = f.to_bits();
let signal_bit = 0b0000_0000_0100_0000_0000_0000_0000_0000;
let signal_bit = 1 << 22;
let signal_bit_clear = (uf & signal_bit) == 0;
f32::is_nan(f) && signal_bit_clear
}
pub fn f64_is_signaling_nan(f: f64) -> bool {
let uf: u64 = f.to_bits();
let signal_bit = 1 << 51;
let signal_bit_clear = (uf & signal_bit) == 0;
f64::is_nan(f) && signal_bit_clear
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_f32_is_signaling_nan() {
use std::f32;
assert!(!f32_is_signaling_nan(3.0));
assert!(!f32_is_signaling_nan(f32::NAN));
assert!(!f32_is_signaling_nan(f32::INFINITY));
assert!(!f32_is_signaling_nan(f32::NEG_INFINITY));
assert!(!f32_is_signaling_nan(f32::MAX));
assert!(!f32_is_signaling_nan(f32::MIN));
let mask: u32 = !(1 << 22);
let uf = f32::NAN.to_bits();
let signaling_nan = f32::from_bits(uf & mask | 1);
assert!(f32_is_signaling_nan(signaling_nan));
}
#[test]
fn test_f64_is_signaling_nan() {
use std::f64;
assert!(!f64_is_signaling_nan(3.0));
assert!(!f64_is_signaling_nan(f64::NAN));
assert!(!f64_is_signaling_nan(f64::INFINITY));
assert!(!f64_is_signaling_nan(f64::NEG_INFINITY));
assert!(!f64_is_signaling_nan(f64::MAX));
assert!(!f64_is_signaling_nan(f64::MIN));
let mask: u64 = !(1 << 51);
let uf = f64::NAN.to_bits();
let signaling_nan = f64::from_bits(uf & mask | 1);
assert!(f64_is_signaling_nan(signaling_nan));
}
}