1 // Adapted from https://github.com/Alexhuszagh/rust-lexical.
2 
3 use crate::lexical::float::ExtendedFloat;
4 use crate::lexical::num::Float;
5 use crate::lexical::rounding::*;
6 
7 // MASKS
8 
9 #[test]
lower_n_mask_test()10 fn lower_n_mask_test() {
11     assert_eq!(lower_n_mask(0u64), 0b0);
12     assert_eq!(lower_n_mask(1u64), 0b1);
13     assert_eq!(lower_n_mask(2u64), 0b11);
14     assert_eq!(lower_n_mask(10u64), 0b1111111111);
15     assert_eq!(lower_n_mask(32u64), 0b11111111111111111111111111111111);
16 }
17 
18 #[test]
lower_n_halfway_test()19 fn lower_n_halfway_test() {
20     assert_eq!(lower_n_halfway(0u64), 0b0);
21     assert_eq!(lower_n_halfway(1u64), 0b1);
22     assert_eq!(lower_n_halfway(2u64), 0b10);
23     assert_eq!(lower_n_halfway(10u64), 0b1000000000);
24     assert_eq!(lower_n_halfway(32u64), 0b10000000000000000000000000000000);
25 }
26 
27 #[test]
nth_bit_test()28 fn nth_bit_test() {
29     assert_eq!(nth_bit(0u64), 0b1);
30     assert_eq!(nth_bit(1u64), 0b10);
31     assert_eq!(nth_bit(2u64), 0b100);
32     assert_eq!(nth_bit(10u64), 0b10000000000);
33     assert_eq!(nth_bit(31u64), 0b10000000000000000000000000000000);
34 }
35 
36 #[test]
internal_n_mask_test()37 fn internal_n_mask_test() {
38     assert_eq!(internal_n_mask(1u64, 0u64), 0b0);
39     assert_eq!(internal_n_mask(1u64, 1u64), 0b1);
40     assert_eq!(internal_n_mask(2u64, 1u64), 0b10);
41     assert_eq!(internal_n_mask(4u64, 2u64), 0b1100);
42     assert_eq!(internal_n_mask(10u64, 2u64), 0b1100000000);
43     assert_eq!(internal_n_mask(10u64, 4u64), 0b1111000000);
44     assert_eq!(
45         internal_n_mask(32u64, 4u64),
46         0b11110000000000000000000000000000
47     );
48 }
49 
50 // NEAREST ROUNDING
51 
52 #[test]
round_nearest_test()53 fn round_nearest_test() {
54     // Check exactly halfway (b'1100000')
55     let mut fp = ExtendedFloat { mant: 0x60, exp: 0 };
56     let (above, halfway) = round_nearest(&mut fp, 6);
57     assert!(!above);
58     assert!(halfway);
59     assert_eq!(fp.mant, 1);
60 
61     // Check above halfway (b'1100001')
62     let mut fp = ExtendedFloat { mant: 0x61, exp: 0 };
63     let (above, halfway) = round_nearest(&mut fp, 6);
64     assert!(above);
65     assert!(!halfway);
66     assert_eq!(fp.mant, 1);
67 
68     // Check below halfway (b'1011111')
69     let mut fp = ExtendedFloat { mant: 0x5F, exp: 0 };
70     let (above, halfway) = round_nearest(&mut fp, 6);
71     assert!(!above);
72     assert!(!halfway);
73     assert_eq!(fp.mant, 1);
74 }
75 
76 // DIRECTED ROUNDING
77 
78 #[test]
round_downward_test()79 fn round_downward_test() {
80     // b0000000
81     let mut fp = ExtendedFloat { mant: 0x00, exp: 0 };
82     round_downward(&mut fp, 6);
83     assert_eq!(fp.mant, 0);
84 
85     // b1000000
86     let mut fp = ExtendedFloat { mant: 0x40, exp: 0 };
87     round_downward(&mut fp, 6);
88     assert_eq!(fp.mant, 1);
89 
90     // b1100000
91     let mut fp = ExtendedFloat { mant: 0x60, exp: 0 };
92     round_downward(&mut fp, 6);
93     assert_eq!(fp.mant, 1);
94 
95     // b1110000
96     let mut fp = ExtendedFloat { mant: 0x70, exp: 0 };
97     round_downward(&mut fp, 6);
98     assert_eq!(fp.mant, 1);
99 }
100 
101 #[test]
round_nearest_tie_even_test()102 fn round_nearest_tie_even_test() {
103     // Check round-up, halfway
104     let mut fp = ExtendedFloat { mant: 0x60, exp: 0 };
105     round_nearest_tie_even(&mut fp, 6);
106     assert_eq!(fp.mant, 2);
107 
108     // Check round-down, halfway
109     let mut fp = ExtendedFloat { mant: 0x20, exp: 0 };
110     round_nearest_tie_even(&mut fp, 6);
111     assert_eq!(fp.mant, 0);
112 
113     // Check round-up, above halfway
114     let mut fp = ExtendedFloat { mant: 0x61, exp: 0 };
115     round_nearest_tie_even(&mut fp, 6);
116     assert_eq!(fp.mant, 2);
117 
118     let mut fp = ExtendedFloat { mant: 0x21, exp: 0 };
119     round_nearest_tie_even(&mut fp, 6);
120     assert_eq!(fp.mant, 1);
121 
122     // Check round-down, below halfway
123     let mut fp = ExtendedFloat { mant: 0x5F, exp: 0 };
124     round_nearest_tie_even(&mut fp, 6);
125     assert_eq!(fp.mant, 1);
126 
127     let mut fp = ExtendedFloat { mant: 0x1F, exp: 0 };
128     round_nearest_tie_even(&mut fp, 6);
129     assert_eq!(fp.mant, 0);
130 }
131 
132 // HIGH-LEVEL
133 
134 #[test]
round_to_float_test()135 fn round_to_float_test() {
136     // Denormal
137     let mut fp = ExtendedFloat {
138         mant: 1 << 63,
139         exp: f64::DENORMAL_EXPONENT - 15,
140     };
141     round_to_float::<f64, _>(&mut fp, round_nearest_tie_even);
142     assert_eq!(fp.mant, 1 << 48);
143     assert_eq!(fp.exp, f64::DENORMAL_EXPONENT);
144 
145     // Halfway, round-down (b'1000000000000000000000000000000000000000000000000000010000000000')
146     let mut fp = ExtendedFloat {
147         mant: 0x8000000000000400,
148         exp: -63,
149     };
150     round_to_float::<f64, _>(&mut fp, round_nearest_tie_even);
151     assert_eq!(fp.mant, 1 << 52);
152     assert_eq!(fp.exp, -52);
153 
154     // Halfway, round-up (b'1000000000000000000000000000000000000000000000000000110000000000')
155     let mut fp = ExtendedFloat {
156         mant: 0x8000000000000C00,
157         exp: -63,
158     };
159     round_to_float::<f64, _>(&mut fp, round_nearest_tie_even);
160     assert_eq!(fp.mant, (1 << 52) + 2);
161     assert_eq!(fp.exp, -52);
162 
163     // Above halfway
164     let mut fp = ExtendedFloat {
165         mant: 0x8000000000000401,
166         exp: -63,
167     };
168     round_to_float::<f64, _>(&mut fp, round_nearest_tie_even);
169     assert_eq!(fp.mant, (1 << 52) + 1);
170     assert_eq!(fp.exp, -52);
171 
172     let mut fp = ExtendedFloat {
173         mant: 0x8000000000000C01,
174         exp: -63,
175     };
176     round_to_float::<f64, _>(&mut fp, round_nearest_tie_even);
177     assert_eq!(fp.mant, (1 << 52) + 2);
178     assert_eq!(fp.exp, -52);
179 
180     // Below halfway
181     let mut fp = ExtendedFloat {
182         mant: 0x80000000000003FF,
183         exp: -63,
184     };
185     round_to_float::<f64, _>(&mut fp, round_nearest_tie_even);
186     assert_eq!(fp.mant, 1 << 52);
187     assert_eq!(fp.exp, -52);
188 
189     let mut fp = ExtendedFloat {
190         mant: 0x8000000000000BFF,
191         exp: -63,
192     };
193     round_to_float::<f64, _>(&mut fp, round_nearest_tie_even);
194     assert_eq!(fp.mant, (1 << 52) + 1);
195     assert_eq!(fp.exp, -52);
196 }
197 
198 #[test]
avoid_overflow_test()199 fn avoid_overflow_test() {
200     // Avoid overflow, fails by 1
201     let mut fp = ExtendedFloat {
202         mant: 0xFFFFFFFFFFFF,
203         exp: f64::MAX_EXPONENT + 5,
204     };
205     avoid_overflow::<f64>(&mut fp);
206     assert_eq!(fp.mant, 0xFFFFFFFFFFFF);
207     assert_eq!(fp.exp, f64::MAX_EXPONENT + 5);
208 
209     // Avoid overflow, succeeds
210     let mut fp = ExtendedFloat {
211         mant: 0xFFFFFFFFFFFF,
212         exp: f64::MAX_EXPONENT + 4,
213     };
214     avoid_overflow::<f64>(&mut fp);
215     assert_eq!(fp.mant, 0x1FFFFFFFFFFFE0);
216     assert_eq!(fp.exp, f64::MAX_EXPONENT - 1);
217 }
218 
219 #[test]
round_to_native_test()220 fn round_to_native_test() {
221     // Overflow
222     let mut fp = ExtendedFloat {
223         mant: 0xFFFFFFFFFFFF,
224         exp: f64::MAX_EXPONENT + 4,
225     };
226     round_to_native::<f64, _>(&mut fp, round_nearest_tie_even);
227     assert_eq!(fp.mant, 0x1FFFFFFFFFFFE0);
228     assert_eq!(fp.exp, f64::MAX_EXPONENT - 1);
229 
230     // Need denormal
231     let mut fp = ExtendedFloat {
232         mant: 1,
233         exp: f64::DENORMAL_EXPONENT + 48,
234     };
235     round_to_native::<f64, _>(&mut fp, round_nearest_tie_even);
236     assert_eq!(fp.mant, 1 << 48);
237     assert_eq!(fp.exp, f64::DENORMAL_EXPONENT);
238 
239     // Halfway, round-down (b'10000000000000000000000000000000000000000000000000000100000')
240     let mut fp = ExtendedFloat {
241         mant: 0x400000000000020,
242         exp: -58,
243     };
244     round_to_native::<f64, _>(&mut fp, round_nearest_tie_even);
245     assert_eq!(fp.mant, 1 << 52);
246     assert_eq!(fp.exp, -52);
247 
248     // Halfway, round-up (b'10000000000000000000000000000000000000000000000000001100000')
249     let mut fp = ExtendedFloat {
250         mant: 0x400000000000060,
251         exp: -58,
252     };
253     round_to_native::<f64, _>(&mut fp, round_nearest_tie_even);
254     assert_eq!(fp.mant, (1 << 52) + 2);
255     assert_eq!(fp.exp, -52);
256 
257     // Above halfway
258     let mut fp = ExtendedFloat {
259         mant: 0x400000000000021,
260         exp: -58,
261     };
262     round_to_native::<f64, _>(&mut fp, round_nearest_tie_even);
263     assert_eq!(fp.mant, (1 << 52) + 1);
264     assert_eq!(fp.exp, -52);
265 
266     let mut fp = ExtendedFloat {
267         mant: 0x400000000000061,
268         exp: -58,
269     };
270     round_to_native::<f64, _>(&mut fp, round_nearest_tie_even);
271     assert_eq!(fp.mant, (1 << 52) + 2);
272     assert_eq!(fp.exp, -52);
273 
274     // Below halfway
275     let mut fp = ExtendedFloat {
276         mant: 0x40000000000001F,
277         exp: -58,
278     };
279     round_to_native::<f64, _>(&mut fp, round_nearest_tie_even);
280     assert_eq!(fp.mant, 1 << 52);
281     assert_eq!(fp.exp, -52);
282 
283     let mut fp = ExtendedFloat {
284         mant: 0x40000000000005F,
285         exp: -58,
286     };
287     round_to_native::<f64, _>(&mut fp, round_nearest_tie_even);
288     assert_eq!(fp.mant, (1 << 52) + 1);
289     assert_eq!(fp.exp, -52);
290 
291     // Underflow
292     // Adapted from failures in strtod.
293     let mut fp = ExtendedFloat {
294         exp: -1139,
295         mant: 18446744073709550712,
296     };
297     round_to_native::<f64, _>(&mut fp, round_nearest_tie_even);
298     assert_eq!(fp.mant, 0);
299     assert_eq!(fp.exp, 0);
300 
301     let mut fp = ExtendedFloat {
302         exp: -1139,
303         mant: 18446744073709551460,
304     };
305     round_to_native::<f64, _>(&mut fp, round_nearest_tie_even);
306     assert_eq!(fp.mant, 0);
307     assert_eq!(fp.exp, 0);
308 
309     let mut fp = ExtendedFloat {
310         exp: -1138,
311         mant: 9223372036854776103,
312     };
313     round_to_native::<f64, _>(&mut fp, round_nearest_tie_even);
314     assert_eq!(fp.mant, 1);
315     assert_eq!(fp.exp, -1074);
316 }
317