float_cmp/
ulps.rs
1#[cfg(feature = "num-traits")]
5use num_traits::NumCast;
6
7#[inline]
8fn f32_ordered_bits(f: f32) -> u32 {
9 const SIGN_BIT: u32 = 1 << 31;
10 let bits = f.to_bits();
11 if bits & SIGN_BIT != 0 {
12 !bits
13 } else {
14 bits ^ SIGN_BIT
15 }
16}
17
18#[inline]
19fn f64_ordered_bits(f: f64) -> u64 {
20 const SIGN_BIT: u64 = 1 << 63;
21 let bits = f.to_bits();
22 if bits & SIGN_BIT != 0 {
23 !bits
24 } else {
25 bits ^ SIGN_BIT
26 }
27}
28
29#[cfg(feature = "num-traits")]
32pub trait Ulps {
33 type U: Copy + NumCast;
34
35 fn ulps(&self, other: &Self) -> <Self as Ulps>::U;
39
40 fn next(&self) -> Self;
42
43 fn prev(&self) -> Self;
45}
46
47#[cfg(not(feature = "num-traits"))]
48pub trait Ulps {
49 type U: Copy;
50
51 fn ulps(&self, other: &Self) -> <Self as Ulps>::U;
55
56 fn next(&self) -> Self;
58
59 fn prev(&self) -> Self;
61}
62
63impl Ulps for f32 {
64 type U = i32;
65
66 fn ulps(&self, other: &f32) -> i32 {
67 let ai32: i32 = f32_ordered_bits(*self) as i32;
75 let bi32: i32 = f32_ordered_bits(*other) as i32;
76
77 ai32.wrapping_sub(bi32)
78 }
79
80 fn next(&self) -> Self {
81 if self.is_infinite() && *self > 0.0 {
82 *self
83 } else if *self == -0.0 && self.is_sign_negative() {
84 0.0
85 } else {
86 let mut u = self.to_bits();
87 if *self >= 0.0 {
88 u += 1;
89 } else {
90 u -= 1;
91 }
92 f32::from_bits(u)
93 }
94 }
95
96 fn prev(&self) -> Self {
97 if self.is_infinite() && *self < 0.0 {
98 *self
99 } else if *self == 0.0 && self.is_sign_positive() {
100 -0.0
101 } else {
102 let mut u = self.to_bits();
103 if *self <= -0.0 {
104 u += 1;
105 } else {
106 u -= 1;
107 }
108 f32::from_bits(u)
109 }
110 }
111}
112
113#[test]
114fn f32_ulps_test1() {
115 let x: f32 = 1000000_f32;
116 let y: f32 = 1000000.1_f32;
117 assert!(x.ulps(&y) == -2);
118}
119
120#[test]
121fn f32_ulps_test2() {
122 let pzero: f32 = f32::from_bits(0x00000000_u32);
123 let nzero: f32 = f32::from_bits(0x80000000_u32);
124 assert_eq!(pzero.ulps(&nzero), 1);
125}
126#[test]
127fn f32_ulps_test3() {
128 let pinf: f32 = f32::from_bits(0x7f800000_u32);
129 let ninf: f32 = f32::from_bits(0xff800000_u32);
130 assert_eq!(pinf.ulps(&ninf), -16777215);
131}
132
133#[test]
134fn f32_ulps_test4() {
135 let x: f32 = f32::from_bits(0x63a7f026_u32);
136 let y: f32 = f32::from_bits(0x63a7f023_u32);
137 assert!(x.ulps(&y) == 3);
138}
139
140#[test]
141fn f32_ulps_test5() {
142 let x: f32 = 2.0;
143 let ulps: i32 = x.to_bits() as i32;
144 let x2: f32 = <f32>::from_bits(ulps as u32);
145 assert_eq!(x, x2);
146}
147
148#[test]
149fn f32_ulps_test6() {
150 let negzero: f32 = -0.;
151 let zero: f32 = 0.;
152 assert_eq!(negzero.next(), zero);
153 assert_eq!(zero.prev(), negzero);
154 assert!(negzero.prev() < 0.0);
155 assert!(zero.next() > 0.0);
156}
157
158impl Ulps for f64 {
159 type U = i64;
160
161 fn ulps(&self, other: &f64) -> i64 {
162 let ai64: i64 = f64_ordered_bits(*self) as i64;
170 let bi64: i64 = f64_ordered_bits(*other) as i64;
171
172 ai64.wrapping_sub(bi64)
173 }
174
175 fn next(&self) -> Self {
176 if self.is_infinite() && *self > 0.0 {
177 *self
178 } else if *self == -0.0 && self.is_sign_negative() {
179 0.0
180 } else {
181 let mut u = self.to_bits();
182 if *self >= 0.0 {
183 u += 1;
184 } else {
185 u -= 1;
186 }
187 f64::from_bits(u)
188 }
189 }
190
191 fn prev(&self) -> Self {
192 if self.is_infinite() && *self < 0.0 {
193 *self
194 } else if *self == 0.0 && self.is_sign_positive() {
195 -0.0
196 } else {
197 let mut u = self.to_bits();
198 if *self <= -0.0 {
199 u += 1;
200 } else {
201 u -= 1;
202 }
203 f64::from_bits(u)
204 }
205 }
206}
207
208#[test]
209fn f64_ulps_test1() {
210 let x: f64 = 1000000_f64;
211 let y: f64 = 1000000.00000001_f64;
212 assert!(x.ulps(&y) == -86);
213}
214
215#[test]
216fn f64_ulps_test2() {
217 let pzero: f64 = f64::from_bits(0x0000000000000000_u64);
218 let nzero: f64 = f64::from_bits(0x8000000000000000_u64);
219 assert_eq!(pzero.ulps(&nzero), 1);
220}
221#[test]
222fn f64_ulps_test3() {
223 let pinf: f64 = f64::from_bits(0x7f80000000000000_u64);
224 let ninf: f64 = f64::from_bits(0xff80000000000000_u64);
225 assert_eq!(pinf.ulps(&ninf), -72057594037927935);
226}
227
228#[test]
229fn f64_ulps_test4() {
230 let x: f64 = f64::from_bits(0xd017f6cc63a7f026_u64);
231 let y: f64 = f64::from_bits(0xd017f6cc63a7f023_u64);
232 assert!(x.ulps(&y) == -3);
233}
234
235#[test]
236fn f64_ulps_test5() {
237 let x: f64 = 2.0;
238 let ulps: i64 = x.to_bits() as i64;
239 let x2: f64 = <f64>::from_bits(ulps as u64);
240 assert_eq!(x, x2);
241}
242
243#[test]
244fn f64_ulps_test6() {
245 let negzero: f64 = -0.;
246 let zero: f64 = 0.;
247 assert_eq!(negzero.next(), zero);
248 assert_eq!(zero.prev(), negzero);
249 assert!(negzero.prev() < 0.0);
250 assert!(zero.next() > 0.0);
251}