Skip to content

Commit

Permalink
FIX: ulps() zero-crossing
Browse files Browse the repository at this point in the history
  • Loading branch information
mikedilger committed Mar 11, 2024
1 parent a898478 commit 6a9facf
Showing 1 changed file with 31 additions and 9 deletions.
40 changes: 31 additions & 9 deletions src/ulps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,28 @@
#[cfg(feature = "num_traits")]
use num_traits::NumCast;

#[inline]
fn f32_ordered_bits(f: f32) -> u32 {
const SIGN_BIT: u32 = 1 << 31;
let bits = f.to_bits();
if bits & SIGN_BIT != 0 {
!bits
} else {
bits ^ SIGN_BIT
}
}

#[inline]
fn f64_ordered_bits(f: f64) -> u64 {
const SIGN_BIT: u64 = 1 << 63;
let bits = f.to_bits();
if bits & SIGN_BIT != 0 {
!bits
} else {
bits ^ SIGN_BIT
}
}

/// A trait for floating point numbers which computes the number of representable
/// values or ULPs (Units of Least Precision) that separate the two given values.
#[cfg(feature = "num_traits")]
Expand Down Expand Up @@ -49,8 +71,8 @@ impl Ulps for f32 {
// two floats are

// Setup integer representations of the input
let ai32: i32 = self.to_bits() as i32;
let bi32: i32 = other.to_bits() as i32;
let ai32: i32 = f32_ordered_bits(*self) as i32;
let bi32: i32 = f32_ordered_bits(*other) as i32;

ai32.wrapping_sub(bi32)
}
Expand Down Expand Up @@ -99,13 +121,13 @@ fn f32_ulps_test1() {
fn f32_ulps_test2() {
let pzero: f32 = f32::from_bits(0x00000000_u32);
let nzero: f32 = f32::from_bits(0x80000000_u32);
assert!(pzero.ulps(&nzero) == -2147483648);
assert_eq!(pzero.ulps(&nzero), 1);
}
#[test]
fn f32_ulps_test3() {
let pinf: f32 = f32::from_bits(0x7f800000_u32);
let ninf: f32 = f32::from_bits(0xff800000_u32);
assert!(pinf.ulps(&ninf) == -2147483648);
assert_eq!(pinf.ulps(&ninf), -16777215);
}

#[test]
Expand Down Expand Up @@ -144,8 +166,8 @@ impl Ulps for f64 {
// two floats are

// Setup integer representations of the input
let ai64: i64 = self.to_bits() as i64;
let bi64: i64 = other.to_bits() as i64;
let ai64: i64 = f64_ordered_bits(*self) as i64;
let bi64: i64 = f64_ordered_bits(*other) as i64;

ai64.wrapping_sub(bi64)
}
Expand Down Expand Up @@ -194,20 +216,20 @@ fn f64_ulps_test1() {
fn f64_ulps_test2() {
let pzero: f64 = f64::from_bits(0x0000000000000000_u64);
let nzero: f64 = f64::from_bits(0x8000000000000000_u64);
assert!(pzero.ulps(&nzero) == -9223372036854775808i64);
assert_eq!(pzero.ulps(&nzero), 1);
}
#[test]
fn f64_ulps_test3() {
let pinf: f64 = f64::from_bits(0x7f80000000000000_u64);
let ninf: f64 = f64::from_bits(0xff80000000000000_u64);
assert!(pinf.ulps(&ninf) == -9223372036854775808i64);
assert_eq!(pinf.ulps(&ninf), -72057594037927935);
}

#[test]
fn f64_ulps_test4() {
let x: f64 = f64::from_bits(0xd017f6cc63a7f026_u64);
let y: f64 = f64::from_bits(0xd017f6cc63a7f023_u64);
assert!(x.ulps(&y) == 3);
assert!(x.ulps(&y) == -3);
}

#[test]
Expand Down

0 comments on commit 6a9facf

Please sign in to comment.