1use core::num::FpCategory;
6
7use crate::{
8 Approximation::{self, *},
9 Sign::{self, *},
10};
11
12pub trait BitTest {
34 fn bit_len(&self) -> usize;
48
49 fn bit(&self, n: usize) -> bool;
51}
52
53pub trait PowerOfTwo {
64 fn is_power_of_two(&self) -> bool;
66 fn next_power_of_two(self) -> Self;
68}
69
70macro_rules! impl_bit_ops_for_uint {
71 ($($T:ty)*) => {$(
72 impl BitTest for $T {
73 #[inline]
74 fn bit_len(&self) -> usize {
75 (<$T>::BITS - self.leading_zeros()) as usize
76 }
77 #[inline]
78 fn bit(&self, position: usize) -> bool {
79 if position >= <$T>::BITS as usize {
80 return false;
81 } else {
82 self & (1 << position) > 0
83 }
84 }
85 }
86
87 impl PowerOfTwo for $T {
88 #[inline]
89 fn is_power_of_two(&self) -> bool {
90 <$T>::is_power_of_two(*self)
91 }
92 #[inline]
93 fn next_power_of_two(self) -> $T {
94 <$T>::next_power_of_two(self)
95 }
96 }
97 )*}
98}
99impl_bit_ops_for_uint!(u8 u16 u32 u64 u128 usize);
100
101macro_rules! impl_bit_ops_for_int {
102 ($($T:ty)*) => {$(
103 impl BitTest for $T {
104 #[inline]
105 fn bit_len(&self) -> usize {
106 self.unsigned_abs().bit_len()
107 }
108 #[inline]
109 fn bit(&self, position: usize) -> bool {
110 if position >= <$T>::BITS as usize {
111 return self < &0;
112 } else {
113 self & (1 << position) != 0
114 }
115 }
116 }
117 )*}
118}
119impl_bit_ops_for_int!(i8 i16 i32 i64 i128 isize);
120
121pub trait FloatEncoding {
140 type Mantissa;
142 type Exponent;
144
145 fn decode(self) -> Result<(Self::Mantissa, Self::Exponent), FpCategory>;
150
151 fn encode(mantissa: Self::Mantissa, exponent: Self::Exponent) -> Approximation<Self, Sign>
162 where
163 Self: Sized;
164}
165
166#[inline]
169fn round_to_even_adjustment(bits: u8) -> bool {
170 bits >= 0b110 || bits == 0b011
171}
172
173impl FloatEncoding for f32 {
174 type Mantissa = i32;
175 type Exponent = i16;
176
177 #[inline]
178 fn decode(self) -> Result<(i32, i16), FpCategory> {
179 let bits: u32 = self.to_bits();
180 let sign_bit = bits >> 31;
181 let mantissa_bits = bits & 0x7fffff;
182
183 let mut exponent = ((bits >> 23) & 0xff) as i16;
185 if exponent == 0xff {
186 return if mantissa_bits != 0 {
187 Err(FpCategory::Nan)
188 } else {
189 Err(FpCategory::Infinite)
190 };
191 }
192
193 let mantissa = if exponent == 0 {
195 exponent = -126 - 23;
197 mantissa_bits
198 } else {
199 exponent -= 127 + 23; mantissa_bits | 0x800000
202 } as i32;
203
204 let sign = Sign::from(sign_bit > 0);
205 Ok((mantissa * sign, exponent))
206 }
207
208 #[inline]
209 fn encode(mantissa: i32, exponent: i16) -> Approximation<Self, Sign> {
210 if mantissa == 0 {
211 return Exact(0f32);
212 }
213
214 let sign = (mantissa < 0) as u32;
216 let mut mantissa = mantissa.unsigned_abs();
217
218 let zeros = mantissa.leading_zeros();
219 let top_bit = (u32::BITS - zeros) as i32 + exponent as i32;
220
221 if top_bit > 128 {
222 return if sign == 0 {
224 Inexact(f32::INFINITY, Sign::Positive)
225 } else {
226 Inexact(f32::NEG_INFINITY, Sign::Negative)
227 };
228 } else if top_bit < -125 - 23 {
229 return if sign == 0 {
231 Inexact(0f32, Sign::Negative)
232 } else {
233 Inexact(-0f32, Sign::Positive)
234 };
235 };
236
237 let bits; let round_bits; if top_bit <= -125 {
240 let shift = exponent + 126 + 23;
245 if shift >= 0 {
246 round_bits = 0; mantissa <<= shift as u32;
248 } else {
249 let shifted = mantissa << (30 + shift) as u32;
250 round_bits = (shifted >> 28 & 0b110) as u8 | ((shifted & 0xfffffff) != 0) as u8;
251 mantissa >>= (-shift) as u32;
252 }
253
254 bits = (sign << 31) | mantissa;
256 } else {
257 if mantissa == 1 {
260 mantissa = 0; } else {
262 mantissa <<= zeros + 1;
263 }
264
265 let exponent = (exponent + 127 + u32::BITS as i16) as u32 - zeros - 1;
267
268 bits = (sign << 31) | (exponent << 23) | (mantissa >> 9);
270
271 round_bits = ((mantissa >> 7) & 0b110) as u8 | ((mantissa & 0x7f) != 0) as u8;
273 };
274
275 if round_bits & 0b11 == 0 {
276 Exact(f32::from_bits(bits))
278 } else {
279 let sign = Sign::from(sign > 0);
280 if round_to_even_adjustment(round_bits) {
281 Inexact(f32::from_bits(bits + 1), Positive * sign)
284 } else {
285 Inexact(f32::from_bits(bits), Negative * sign)
286 }
287 }
288 }
289}
290
291impl FloatEncoding for f64 {
292 type Mantissa = i64;
293 type Exponent = i16;
294
295 #[inline]
296 fn decode(self) -> Result<(i64, i16), FpCategory> {
297 let bits: u64 = self.to_bits();
298 let sign_bit = bits >> 63;
299 let mantissa_bits = bits & 0xfffffffffffff;
300
301 let mut exponent = ((bits >> 52) & 0x7ff) as i16;
303 if exponent == 0x7ff {
304 return if mantissa_bits != 0 {
305 Err(FpCategory::Nan)
306 } else {
307 Err(FpCategory::Infinite)
308 };
309 }
310
311 let mantissa = if exponent == 0 {
313 exponent = -1022 - 52;
315 mantissa_bits
316 } else {
317 exponent -= 1023 + 52; mantissa_bits | 0x10000000000000
320 } as i64;
321
322 if sign_bit == 0 {
323 Ok((mantissa, exponent))
324 } else {
325 Ok((-mantissa, exponent))
326 }
327 }
328
329 #[inline]
330 fn encode(mantissa: i64, exponent: i16) -> Approximation<Self, Sign> {
331 if mantissa == 0 {
332 return Exact(0f64);
333 }
334
335 let sign = (mantissa < 0) as u64;
337 let mut mantissa = mantissa.unsigned_abs();
338
339 let zeros = mantissa.leading_zeros();
340 let top_bit = (u64::BITS - zeros) as i32 + exponent as i32;
341
342 if top_bit > 1024 {
343 return if sign == 0 {
345 Inexact(f64::INFINITY, Sign::Positive)
346 } else {
347 Inexact(f64::NEG_INFINITY, Sign::Negative)
348 };
349 } else if top_bit < -1022 - 52 {
350 return if sign == 0 {
352 Inexact(0f64, Sign::Negative)
353 } else {
354 Inexact(-0f64, Sign::Positive)
355 };
356 };
357
358 let bits; let round_bits; if top_bit <= -1022 {
361 let shift = exponent + 1022 + 52;
366 if shift >= 0 {
367 round_bits = 0; mantissa <<= shift as u32;
369 } else {
370 let shifted = mantissa << (62 + shift) as u64;
371 round_bits =
372 (shifted >> 60 & 0b110) as u8 | ((shifted & 0xfffffffffffffff) != 0) as u8;
373 mantissa >>= (-shift) as u32;
374 }
375
376 bits = (sign << 63) | mantissa;
378 } else {
379 if mantissa == 1 {
382 mantissa = 0; } else {
384 mantissa <<= zeros + 1;
385 }
386
387 let exponent = (exponent + 1023 + u64::BITS as i16) as u64 - zeros as u64 - 1;
389
390 bits = (sign << 63) | (exponent << 52) | (mantissa >> 12);
392
393 round_bits = ((mantissa >> 10) & 0b110) as u8 | ((mantissa & 0x3ff) != 0) as u8;
395 };
396
397 if round_bits & 0b11 == 0 {
398 Exact(f64::from_bits(bits))
400 } else {
401 let sign = Sign::from(sign > 0);
402 if round_to_even_adjustment(round_bits) {
403 Inexact(f64::from_bits(bits + 1), Positive * sign)
406 } else {
407 Inexact(f64::from_bits(bits), Negative * sign)
408 }
409 }
410 }
411}
412
413#[cfg(test)]
414mod tests {
415 use super::*;
416
417 #[test]
418 fn test_float_encoding() {
419 assert_eq!(f32::INFINITY.decode(), Err(FpCategory::Infinite));
421 assert_eq!(f32::NEG_INFINITY.decode(), Err(FpCategory::Infinite));
422 assert_eq!(f32::NAN.decode(), Err(FpCategory::Nan));
423 assert_eq!(f64::INFINITY.decode(), Err(FpCategory::Infinite));
424 assert_eq!(f64::NEG_INFINITY.decode(), Err(FpCategory::Infinite));
425 assert_eq!(f64::NAN.decode(), Err(FpCategory::Nan));
426
427 let f32_cases = [
429 0.,
430 -1.,
431 1.,
432 f32::MIN,
433 f32::MAX,
434 f32::MIN_POSITIVE,
435 -f32::MIN_POSITIVE,
436 f32::EPSILON,
437 f32::from_bits(0x1), f32::from_bits(0x7ff), f32::from_bits(0x7fffff), f32::from_bits(0x800000), -123.4567,
442 core::f32::consts::PI,
443 ];
444 for f in f32_cases {
445 let (man, exp) = f.decode().unwrap();
446 assert_eq!(f32::encode(man, exp), Exact(f));
447 }
448
449 let f64_cases = [
450 0.,
451 -1.,
452 1.,
453 f64::MIN,
454 f64::MAX,
455 f64::MIN_POSITIVE,
456 -f64::MIN_POSITIVE,
457 f64::EPSILON,
458 f64::from_bits(0x1), f64::from_bits(0x7fffff), f64::from_bits(0xfffffffffffff), f64::from_bits(0x10000000000000), -123456.789012345,
463 core::f64::consts::PI,
464 ];
465 for f in f64_cases {
466 let (man, exp) = f.decode().unwrap();
467 assert_eq!(f64::encode(man, exp), Exact(f));
468 }
469
470 assert_eq!(f32::encode(1, 128), Inexact(f32::INFINITY, Sign::Positive));
472 assert_eq!(f32::encode(-1, 128), Inexact(f32::NEG_INFINITY, Sign::Negative));
473 assert_eq!(f32::encode(1, -150), Inexact(0f32, Sign::Negative));
474 assert_eq!(f32::encode(-1, -150), Inexact(-0f32, Sign::Positive));
475 assert_eq!(f64::encode(1, 1024), Inexact(f64::INFINITY, Sign::Positive));
476 assert_eq!(f64::encode(-1, 1024), Inexact(f64::NEG_INFINITY, Sign::Negative));
477 assert_eq!(f64::encode(1, -1075), Inexact(0f64, Sign::Negative));
478 assert_eq!(f64::encode(-1, -1075), Inexact(-0f64, Sign::Positive));
479
480 assert_eq!(f32::encode(256, 32759), Inexact(f32::INFINITY, Sign::Positive));
485 assert_eq!(f64::encode(256, 32759), Inexact(f64::INFINITY, Sign::Positive));
486
487 assert_eq!(f32::encode(3, -150), Inexact(f32::from_bits(0x00000002), Sign::Positive));
489 assert_eq!(f32::encode(-5, -150), Inexact(f32::from_bits(0x80000002), Sign::Positive));
490 assert_eq!(f32::encode(i32::MAX, 50), Inexact(f32::from_bits(0x68000000), Sign::Positive));
491 assert_eq!(
492 f32::encode(i32::MAX, -150),
493 Inexact(f32::from_bits(0x04000000), Sign::Positive)
494 );
495 assert_eq!(
496 f32::encode(i32::MAX, -160),
497 Inexact(f32::from_bits(0x00100000), Sign::Positive)
498 );
499 assert_eq!(
500 f32::encode(i32::MAX, -170),
501 Inexact(f32::from_bits(0x00000400), Sign::Positive)
502 );
503 assert_eq!(
504 f64::encode(3, -1075),
505 Inexact(f64::from_bits(0x0000000000000002), Sign::Positive)
506 );
507 assert_eq!(
508 f64::encode(-5, -1075),
509 Inexact(f64::from_bits(0x8000000000000002), Sign::Positive)
510 );
511 assert_eq!(
512 f64::encode(i64::MAX, 500),
513 Inexact(f64::from_bits(0x6320000000000000), Sign::Positive)
514 );
515 assert_eq!(
516 f64::encode(i64::MAX, -1075),
517 Inexact(f64::from_bits(0x00b0000000000000), Sign::Positive)
518 );
519 assert_eq!(
520 f64::encode(i64::MAX, -1095),
521 Inexact(f64::from_bits(0x0000040000000000), Sign::Positive)
522 );
523 assert_eq!(f64::encode(i64::MAX, -1115), Inexact(f64::from_bits(0x400000), Sign::Positive));
524
525 assert_eq!(f32::encode(1, 0), Exact(1f32));
527 assert_eq!(f64::encode(1, 0), Exact(1f64));
528 assert_eq!(f32::encode(0x1000000, -173), Exact(f32::from_bits(0x1)));
529 assert_eq!(f64::encode(0x40000000000000, -1128), Exact(f64::from_bits(0x1)));
530 }
531}