1use core::num::FpCategory;
6
7use crate::{
8 Approximation::{self, *},
9 Sign::{self, *},
10};
11
12pub trait BitTest {
33 fn bit_len(&self) -> usize;
47
48 fn bit(&self, n: usize) -> bool;
50}
51
52pub trait PowerOfTwo {
63 fn is_power_of_two(&self) -> bool;
65 fn next_power_of_two(self) -> Self;
67}
68
69macro_rules! impl_bit_ops_for_uint {
70 ($($T:ty)*) => {$(
71 impl BitTest for $T {
72 #[inline]
73 fn bit_len(&self) -> usize {
74 (<$T>::BITS - self.leading_zeros()) as usize
75 }
76 #[inline]
77 fn bit(&self, position: usize) -> bool {
78 if position >= <$T>::BITS as usize {
79 return false;
80 } else {
81 self & (1 << position) > 0
82 }
83 }
84 }
85
86 impl PowerOfTwo for $T {
87 #[inline]
88 fn is_power_of_two(&self) -> bool {
89 <$T>::is_power_of_two(*self)
90 }
91 #[inline]
92 fn next_power_of_two(self) -> $T {
93 <$T>::next_power_of_two(self)
94 }
95 }
96 )*}
97}
98impl_bit_ops_for_uint!(u8 u16 u32 u64 u128 usize);
99
100macro_rules! impl_bit_ops_for_int {
101 ($($T:ty)*) => {$(
102 impl BitTest for $T {
103 #[inline]
104 fn bit_len(&self) -> usize {
105 self.unsigned_abs().bit_len()
106 }
107 #[inline]
108 fn bit(&self, position: usize) -> bool {
109 if position >= <$T>::BITS as usize {
110 return self < &0;
111 } else {
112 self & (1 << position) > 0
113 }
114 }
115 }
116 )*}
117}
118impl_bit_ops_for_int!(i8 i16 i32 i64 i128 isize);
119
120pub trait FloatEncoding {
139 type Mantissa;
140 type Exponent;
141
142 fn decode(self) -> Result<(Self::Mantissa, Self::Exponent), FpCategory>;
147
148 fn encode(mantissa: Self::Mantissa, exponent: Self::Exponent) -> Approximation<Self, Sign>
159 where
160 Self: Sized;
161}
162
163#[inline]
166fn round_to_even_adjustment(bits: u8) -> bool {
167 bits >= 0b110 || bits == 0b011
168}
169
170impl FloatEncoding for f32 {
171 type Mantissa = i32;
172 type Exponent = i16;
173
174 #[inline]
175 fn decode(self) -> Result<(i32, i16), FpCategory> {
176 let bits: u32 = self.to_bits();
177 let sign_bit = bits >> 31;
178 let mantissa_bits = bits & 0x7fffff;
179
180 let mut exponent = ((bits >> 23) & 0xff) as i16;
182 if exponent == 0xff {
183 return if mantissa_bits != 0 {
184 Err(FpCategory::Nan)
185 } else {
186 Err(FpCategory::Infinite)
187 };
188 }
189
190 let mantissa = if exponent == 0 {
192 exponent = -126 - 23;
194 mantissa_bits
195 } else {
196 exponent -= 127 + 23; mantissa_bits | 0x800000
199 } as i32;
200
201 let sign = Sign::from(sign_bit > 0);
202 Ok((mantissa * sign, exponent))
203 }
204
205 #[inline]
206 fn encode(mantissa: i32, exponent: i16) -> Approximation<Self, Sign> {
207 if mantissa == 0 {
208 return Exact(0f32);
209 }
210
211 let sign = (mantissa < 0) as u32;
213 let mut mantissa = mantissa.unsigned_abs();
214
215 let zeros = mantissa.leading_zeros();
216 let top_bit = (u32::BITS - zeros) as i16 + exponent;
217
218 if top_bit > 128 {
219 return if sign == 0 {
221 Inexact(f32::INFINITY, Sign::Positive)
222 } else {
223 Inexact(f32::NEG_INFINITY, Sign::Negative)
224 };
225 } else if top_bit < -125 - 23 {
226 return if sign == 0 {
228 Inexact(0f32, Sign::Negative)
229 } else {
230 Inexact(-0f32, Sign::Positive)
231 };
232 };
233
234 let bits; let round_bits; if top_bit <= -125 {
237 let shift = exponent + 126 + 23;
242 if shift >= 0 {
243 round_bits = 0; mantissa <<= shift as u32;
245 } else {
246 let shifted = mantissa << (30 + shift) as u32;
247 round_bits = (shifted >> 28 & 0b110) as u8 | ((shifted & 0xfffffff) != 0) as u8;
248 mantissa >>= (-shift) as u32;
249 }
250
251 bits = (sign << 31) | mantissa;
253 } else {
254 if mantissa == 1 {
257 mantissa = 0; } else {
259 mantissa <<= zeros + 1;
260 }
261
262 let exponent = (exponent + 127 + u32::BITS as i16) as u32 - zeros - 1;
264
265 bits = (sign << 31) | (exponent << 23) | (mantissa >> 9);
267
268 round_bits = ((mantissa >> 7) & 0b110) as u8 | ((mantissa & 0x7f) != 0) as u8;
270 };
271
272 if round_bits & 0b11 == 0 {
273 Exact(f32::from_bits(bits))
275 } else {
276 let sign = Sign::from(sign > 0);
277 if round_to_even_adjustment(round_bits) {
278 Inexact(f32::from_bits(bits + 1), Positive * sign)
281 } else {
282 Inexact(f32::from_bits(bits), Negative * sign)
283 }
284 }
285 }
286}
287
288impl FloatEncoding for f64 {
289 type Mantissa = i64;
290 type Exponent = i16;
291
292 #[inline]
293 fn decode(self) -> Result<(i64, i16), FpCategory> {
294 let bits: u64 = self.to_bits();
295 let sign_bit = bits >> 63;
296 let mantissa_bits = bits & 0xfffffffffffff;
297
298 let mut exponent = ((bits >> 52) & 0x7ff) as i16;
300 if exponent == 0x7ff {
301 return if mantissa_bits != 0 {
302 Err(FpCategory::Nan)
303 } else {
304 Err(FpCategory::Infinite)
305 };
306 }
307
308 let mantissa = if exponent == 0 {
310 exponent = -1022 - 52;
312 mantissa_bits
313 } else {
314 exponent -= 1023 + 52; mantissa_bits | 0x10000000000000
317 } as i64;
318
319 if sign_bit == 0 {
320 Ok((mantissa, exponent))
321 } else {
322 Ok((-mantissa, exponent))
323 }
324 }
325
326 #[inline]
327 fn encode(mantissa: i64, exponent: i16) -> Approximation<Self, Sign> {
328 if mantissa == 0 {
329 return Exact(0f64);
330 }
331
332 let sign = (mantissa < 0) as u64;
334 let mut mantissa = mantissa.unsigned_abs();
335
336 let zeros = mantissa.leading_zeros();
337 let top_bit = (u64::BITS - zeros) as i16 + exponent;
338
339 if top_bit > 1024 {
340 return if sign == 0 {
342 Inexact(f64::INFINITY, Sign::Positive)
343 } else {
344 Inexact(f64::NEG_INFINITY, Sign::Negative)
345 };
346 } else if top_bit < -1022 - 52 {
347 return if sign == 0 {
349 Inexact(0f64, Sign::Negative)
350 } else {
351 Inexact(-0f64, Sign::Positive)
352 };
353 };
354
355 let bits; let round_bits; if top_bit <= -1022 {
358 let shift = exponent + 1022 + 52;
363 if shift >= 0 {
364 round_bits = 0; mantissa <<= shift as u32;
366 } else {
367 let shifted = mantissa << (62 + shift) as u64;
368 round_bits =
369 (shifted >> 60 & 0b110) as u8 | ((shifted & 0xfffffffffffffff) != 0) as u8;
370 mantissa >>= (-shift) as u32;
371 }
372
373 bits = (sign << 63) | mantissa;
375 } else {
376 if mantissa == 1 {
379 mantissa = 0; } else {
381 mantissa <<= zeros + 1;
382 }
383
384 let exponent = (exponent + 1023 + u64::BITS as i16) as u64 - zeros as u64 - 1;
386
387 bits = (sign << 63) | (exponent << 52) | (mantissa >> 12);
389
390 round_bits = ((mantissa >> 10) & 0b110) as u8 | ((mantissa & 0x3ff) != 0) as u8;
392 };
393
394 if round_bits & 0b11 == 0 {
395 Exact(f64::from_bits(bits))
397 } else {
398 let sign = Sign::from(sign > 0);
399 if round_to_even_adjustment(round_bits) {
400 Inexact(f64::from_bits(bits + 1), Positive * sign)
403 } else {
404 Inexact(f64::from_bits(bits), Negative * sign)
405 }
406 }
407 }
408}
409
410#[cfg(test)]
411mod tests {
412 use super::*;
413
414 #[test]
415 fn test_float_encoding() {
416 assert_eq!(f32::INFINITY.decode(), Err(FpCategory::Infinite));
418 assert_eq!(f32::NEG_INFINITY.decode(), Err(FpCategory::Infinite));
419 assert_eq!(f32::NAN.decode(), Err(FpCategory::Nan));
420 assert_eq!(f64::INFINITY.decode(), Err(FpCategory::Infinite));
421 assert_eq!(f64::NEG_INFINITY.decode(), Err(FpCategory::Infinite));
422 assert_eq!(f64::NAN.decode(), Err(FpCategory::Nan));
423
424 let f32_cases = [
426 0.,
427 -1.,
428 1.,
429 f32::MIN,
430 f32::MAX,
431 f32::MIN_POSITIVE,
432 -f32::MIN_POSITIVE,
433 f32::EPSILON,
434 f32::from_bits(0x1), f32::from_bits(0x7ff), f32::from_bits(0x7fffff), f32::from_bits(0x800000), -123.4567,
439 core::f32::consts::PI,
440 ];
441 for f in f32_cases {
442 let (man, exp) = f.decode().unwrap();
443 assert_eq!(f32::encode(man, exp), Exact(f));
444 }
445
446 let f64_cases = [
447 0.,
448 -1.,
449 1.,
450 f64::MIN,
451 f64::MAX,
452 f64::MIN_POSITIVE,
453 -f64::MIN_POSITIVE,
454 f64::EPSILON,
455 f64::from_bits(0x1), f64::from_bits(0x7fffff), f64::from_bits(0xfffffffffffff), f64::from_bits(0x10000000000000), -123456.789012345,
460 core::f64::consts::PI,
461 ];
462 for f in f64_cases {
463 let (man, exp) = f.decode().unwrap();
464 assert_eq!(f64::encode(man, exp), Exact(f));
465 }
466
467 assert_eq!(f32::encode(1, 128), Inexact(f32::INFINITY, Sign::Positive));
469 assert_eq!(f32::encode(-1, 128), Inexact(f32::NEG_INFINITY, Sign::Negative));
470 assert_eq!(f32::encode(1, -150), Inexact(0f32, Sign::Negative));
471 assert_eq!(f32::encode(-1, -150), Inexact(-0f32, Sign::Positive));
472 assert_eq!(f64::encode(1, 1024), Inexact(f64::INFINITY, Sign::Positive));
473 assert_eq!(f64::encode(-1, 1024), Inexact(f64::NEG_INFINITY, Sign::Negative));
474 assert_eq!(f64::encode(1, -1075), Inexact(0f64, Sign::Negative));
475 assert_eq!(f64::encode(-1, -1075), Inexact(-0f64, Sign::Positive));
476
477 assert_eq!(f32::encode(3, -150), Inexact(f32::from_bits(0x00000002), Sign::Positive));
479 assert_eq!(f32::encode(-5, -150), Inexact(f32::from_bits(0x80000002), Sign::Positive));
480 assert_eq!(f32::encode(i32::MAX, 50), Inexact(f32::from_bits(0x68000000), Sign::Positive));
481 assert_eq!(
482 f32::encode(i32::MAX, -150),
483 Inexact(f32::from_bits(0x04000000), Sign::Positive)
484 );
485 assert_eq!(
486 f32::encode(i32::MAX, -160),
487 Inexact(f32::from_bits(0x00100000), Sign::Positive)
488 );
489 assert_eq!(
490 f32::encode(i32::MAX, -170),
491 Inexact(f32::from_bits(0x00000400), Sign::Positive)
492 );
493 assert_eq!(
494 f64::encode(3, -1075),
495 Inexact(f64::from_bits(0x0000000000000002), Sign::Positive)
496 );
497 assert_eq!(
498 f64::encode(-5, -1075),
499 Inexact(f64::from_bits(0x8000000000000002), Sign::Positive)
500 );
501 assert_eq!(
502 f64::encode(i64::MAX, 500),
503 Inexact(f64::from_bits(0x6320000000000000), Sign::Positive)
504 );
505 assert_eq!(
506 f64::encode(i64::MAX, -1075),
507 Inexact(f64::from_bits(0x00b0000000000000), Sign::Positive)
508 );
509 assert_eq!(
510 f64::encode(i64::MAX, -1095),
511 Inexact(f64::from_bits(0x0000040000000000), Sign::Positive)
512 );
513 assert_eq!(f64::encode(i64::MAX, -1115), Inexact(f64::from_bits(0x400000), Sign::Positive));
514
515 assert_eq!(f32::encode(1, 0), Exact(1f32));
517 assert_eq!(f64::encode(1, 0), Exact(1f64));
518 assert_eq!(f32::encode(0x1000000, -173), Exact(f32::from_bits(0x1)));
519 assert_eq!(f64::encode(0x40000000000000, -1128), Exact(f64::from_bits(0x1)));
520 }
521}