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