1use alloc::vec::Vec;
8use core::cmp::Ordering;
9use core::fmt::{self, Display, Formatter};
10use core::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Sub};
11use core::str::FromStr;
12use libm::Libm;
13#[cfg(feature = "enable-serde")]
14use serde_derive::{Deserialize, Serialize};
15
16pub trait IntoBytes {
19 fn into_bytes(self) -> Vec<u8>;
21}
22
23impl IntoBytes for u8 {
24 fn into_bytes(self) -> Vec<u8> {
25 vec![self]
26 }
27}
28
29impl IntoBytes for i8 {
30 fn into_bytes(self) -> Vec<u8> {
31 vec![self as u8]
32 }
33}
34
35impl IntoBytes for i16 {
36 fn into_bytes(self) -> Vec<u8> {
37 self.to_le_bytes().to_vec()
38 }
39}
40
41impl IntoBytes for i32 {
42 fn into_bytes(self) -> Vec<u8> {
43 self.to_le_bytes().to_vec()
44 }
45}
46
47impl IntoBytes for Vec<u8> {
48 fn into_bytes(self) -> Vec<u8> {
49 self
50 }
51}
52
53#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
58#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
59pub struct Imm64(i64);
60
61impl Imm64 {
62 pub fn new(x: i64) -> Self {
64 Self(x)
65 }
66
67 pub fn wrapping_neg(self) -> Self {
69 Self(self.0.wrapping_neg())
70 }
71
72 pub fn bits(&self) -> i64 {
74 self.0
75 }
76
77 #[must_use]
79 pub(crate) fn mask_to_width(&self, bit_width: u32) -> Self {
80 debug_assert!(bit_width.is_power_of_two());
81
82 if bit_width >= 64 {
83 return *self;
84 }
85
86 let bit_width = i64::from(bit_width);
87 let mask = (1 << bit_width) - 1;
88 let masked = self.0 & mask;
89 Imm64(masked)
90 }
91
92 #[must_use]
95 pub fn sign_extend_from_width(&self, bit_width: u32) -> Self {
96 debug_assert!(
97 bit_width.is_power_of_two(),
98 "{bit_width} is not a power of two"
99 );
100
101 if bit_width >= 64 {
102 return *self;
103 }
104
105 let bit_width = i64::from(bit_width);
106 let delta = 64 - bit_width;
107 let sign_extended = (self.0 << delta) >> delta;
108 Imm64(sign_extended)
109 }
110
111 #[must_use]
114 pub fn zero_extend_from_width(&self, bit_width: u32) -> Self {
115 debug_assert!(
116 bit_width.is_power_of_two(),
117 "{bit_width} is not a power of two"
118 );
119
120 if bit_width >= 64 {
121 return *self;
122 }
123
124 let bit_width = u64::from(bit_width);
125 let delta = 64 - bit_width;
126 let zero_extended = (self.0.cast_unsigned() << delta) >> delta;
127 Imm64(zero_extended.cast_signed())
128 }
129}
130
131impl From<Imm64> for i64 {
132 fn from(val: Imm64) -> i64 {
133 val.0
134 }
135}
136
137impl IntoBytes for Imm64 {
138 fn into_bytes(self) -> Vec<u8> {
139 self.0.to_le_bytes().to_vec()
140 }
141}
142
143impl From<i64> for Imm64 {
144 fn from(x: i64) -> Self {
145 Self(x)
146 }
147}
148
149impl Display for Imm64 {
150 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
151 let x = self.0;
152 if x < 10_000 {
153 write!(f, "{x}")
155 } else {
156 write_hex(x as u64, f)
157 }
158 }
159}
160
161fn parse_i64(s: &str) -> Result<i64, &'static str> {
163 let negative = s.starts_with('-');
164 let s2 = if negative || s.starts_with('+') {
165 &s[1..]
166 } else {
167 s
168 };
169
170 let mut value = parse_u64(s2)?;
171
172 if negative {
174 value = value.wrapping_neg();
175 if value as i64 > 0 {
177 return Err("Negative number too small");
178 }
179 }
180 Ok(value as i64)
181}
182
183impl FromStr for Imm64 {
184 type Err = &'static str;
185
186 fn from_str(s: &str) -> Result<Self, &'static str> {
188 parse_i64(s).map(Self::new)
189 }
190}
191
192#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
197#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
198pub struct Uimm64(u64);
199
200impl Uimm64 {
201 pub fn new(x: u64) -> Self {
203 Self(x)
204 }
205
206 pub fn wrapping_neg(self) -> Self {
208 Self(self.0.wrapping_neg())
209 }
210}
211
212impl From<Uimm64> for u64 {
213 fn from(val: Uimm64) -> u64 {
214 val.0
215 }
216}
217
218impl From<u64> for Uimm64 {
219 fn from(x: u64) -> Self {
220 Self(x)
221 }
222}
223
224fn write_hex(x: u64, f: &mut Formatter) -> fmt::Result {
231 let mut pos = (64 - x.leading_zeros() - 1) & 0xf0;
232 write!(f, "0x{:04x}", (x >> pos) & 0xffff)?;
233 while pos > 0 {
234 pos -= 16;
235 write!(f, "_{:04x}", (x >> pos) & 0xffff)?;
236 }
237 Ok(())
238}
239
240impl Display for Uimm64 {
241 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
242 let x = self.0;
243 if x < 10_000 {
244 write!(f, "{x}")
246 } else {
247 write_hex(x, f)
248 }
249 }
250}
251
252fn parse_u64(s: &str) -> Result<u64, &'static str> {
254 let mut value: u64 = 0;
255 let mut digits = 0;
256
257 if s.starts_with("-0x") {
258 return Err("Invalid character in hexadecimal number");
259 } else if let Some(num) = s.strip_prefix("0x") {
260 for ch in num.chars() {
262 match ch.to_digit(16) {
263 Some(digit) => {
264 digits += 1;
265 if digits > 16 {
266 return Err("Too many hexadecimal digits");
267 }
268 value = (value << 4) | u64::from(digit);
270 }
271 None => {
272 if ch != '_' {
274 return Err("Invalid character in hexadecimal number");
275 }
276 }
277 }
278 }
279 } else {
280 for ch in s.chars() {
282 match ch.to_digit(10) {
283 Some(digit) => {
284 digits += 1;
285 match value.checked_mul(10) {
286 None => return Err("Too large decimal number"),
287 Some(v) => value = v,
288 }
289 match value.checked_add(u64::from(digit)) {
290 None => return Err("Too large decimal number"),
291 Some(v) => value = v,
292 }
293 }
294 None => {
295 if ch != '_' {
297 return Err("Invalid character in decimal number");
298 }
299 }
300 }
301 }
302 }
303
304 if digits == 0 {
305 return Err("No digits in number");
306 }
307
308 Ok(value)
309}
310
311impl FromStr for Uimm64 {
312 type Err = &'static str;
313
314 fn from_str(s: &str) -> Result<Self, &'static str> {
316 parse_u64(s).map(Self::new)
317 }
318}
319
320pub type Uimm8 = u8;
324
325#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
329#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
330pub struct Uimm32(u32);
331
332impl From<Uimm32> for u32 {
333 fn from(val: Uimm32) -> u32 {
334 val.0
335 }
336}
337
338impl From<Uimm32> for u64 {
339 fn from(val: Uimm32) -> u64 {
340 val.0.into()
341 }
342}
343
344impl From<Uimm32> for i64 {
345 fn from(val: Uimm32) -> i64 {
346 i64::from(val.0)
347 }
348}
349
350impl From<u32> for Uimm32 {
351 fn from(x: u32) -> Self {
352 Self(x)
353 }
354}
355
356impl Display for Uimm32 {
357 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
358 if self.0 < 10_000 {
359 write!(f, "{}", self.0)
360 } else {
361 write_hex(u64::from(self.0), f)
362 }
363 }
364}
365
366impl FromStr for Uimm32 {
367 type Err = &'static str;
368
369 fn from_str(s: &str) -> Result<Self, &'static str> {
371 parse_i64(s).and_then(|x| {
372 if 0 <= x && x <= i64::from(u32::MAX) {
373 Ok(Self(x as u32))
374 } else {
375 Err("Uimm32 out of range")
376 }
377 })
378 }
379}
380
381#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
385#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
386pub struct V128Imm(pub [u8; 16]);
387
388impl V128Imm {
389 pub fn bytes(&self) -> impl Iterator<Item = &u8> {
391 self.0.iter()
392 }
393
394 pub fn to_vec(self) -> Vec<u8> {
396 self.0.to_vec()
397 }
398
399 pub fn as_slice(&self) -> &[u8] {
401 &self.0[..]
402 }
403}
404
405impl From<&[u8]> for V128Imm {
406 fn from(slice: &[u8]) -> Self {
407 assert_eq!(slice.len(), 16);
408 let mut buffer = [0; 16];
409 buffer.copy_from_slice(slice);
410 Self(buffer)
411 }
412}
413
414impl From<u128> for V128Imm {
415 fn from(val: u128) -> Self {
416 V128Imm(val.to_le_bytes())
417 }
418}
419
420#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
425#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
426pub struct Offset32(i32);
427
428impl Offset32 {
429 pub fn new(x: i32) -> Self {
431 Self(x)
432 }
433
434 pub fn try_from_i64(x: i64) -> Option<Self> {
436 let x = i32::try_from(x).ok()?;
437 Some(Self::new(x))
438 }
439
440 pub fn try_add_i64(self, x: i64) -> Option<Self> {
442 let x = i32::try_from(x).ok()?;
443 let ret = self.0.checked_add(x)?;
444 Some(Self::new(ret))
445 }
446}
447
448impl From<Offset32> for i32 {
449 fn from(val: Offset32) -> i32 {
450 val.0
451 }
452}
453
454impl From<Offset32> for i64 {
455 fn from(val: Offset32) -> i64 {
456 i64::from(val.0)
457 }
458}
459
460impl From<i32> for Offset32 {
461 fn from(x: i32) -> Self {
462 Self(x)
463 }
464}
465
466impl From<u8> for Offset32 {
467 fn from(val: u8) -> Offset32 {
468 Self(val.into())
469 }
470}
471
472impl Display for Offset32 {
473 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
474 if self.0 == 0 {
476 return Ok(());
477 }
478
479 write!(f, "{}", if self.0 < 0 { '-' } else { '+' })?;
481
482 let val = i64::from(self.0).abs();
483 if val < 10_000 {
484 write!(f, "{val}")
485 } else {
486 write_hex(val as u64, f)
487 }
488 }
489}
490
491impl FromStr for Offset32 {
492 type Err = &'static str;
493
494 fn from_str(s: &str) -> Result<Self, &'static str> {
496 if !(s.starts_with('-') || s.starts_with('+')) {
497 return Err("Offset must begin with sign");
498 }
499 parse_i64(s).and_then(|x| {
500 if i64::from(i32::MIN) <= x && x <= i64::from(i32::MAX) {
501 Ok(Self::new(x as i32))
502 } else {
503 Err("Offset out of range")
504 }
505 })
506 }
507}
508
509macro_rules! ignore {
511 ($($t:tt)*) => {};
512}
513
514macro_rules! ieee_float {
515 (
516 name = $name:ident,
517 bits = $bits:literal,
518 significand_bits = $significand_bits:literal,
519 bits_ty = $bits_ty:ident,
520 float_ty = $float_ty:ident,
521 $(as_float = $as_float:ident,)?
522 $(rust_type_not_stable = $rust_type_not_stable:ident,)?
523 ) => {
524 #[doc = concat!("binary", stringify!($bits))]
526 #[doc = stringify!($bits_ty)]
528 #[doc = stringify!($float_ty)]
532 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
540 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
541 #[repr(C)]
542 pub struct $name {
543 bits: $bits_ty
544 }
545
546 impl $name {
547 const BITS: u8 = $bits;
548 const SIGNIFICAND_BITS: u8 = $significand_bits;
549 const EXPONENT_BITS: u8 = Self::BITS - Self::SIGNIFICAND_BITS - 1;
550 const SIGN_MASK: $bits_ty = 1 << (Self::EXPONENT_BITS + Self::SIGNIFICAND_BITS);
551 const SIGNIFICAND_MASK: $bits_ty = $bits_ty::MAX >> (Self::EXPONENT_BITS + 1);
552 const EXPONENT_MASK: $bits_ty = !Self::SIGN_MASK & !Self::SIGNIFICAND_MASK;
553 pub const NAN: Self = Self::with_bits(Self::EXPONENT_MASK | (1 << (Self::SIGNIFICAND_BITS - 1)));
555
556 #[doc = concat!("`", stringify!($name), "`")]
558 pub const fn with_bits(bits: $bits_ty) -> Self {
560 Self { bits }
561 }
562
563 pub fn bits(self) -> $bits_ty {
565 self.bits
566 }
567
568 $(
569 #[doc = concat!("`", stringify!($name), "`")]
571 pub fn with_float(x: $float_ty) -> Self {
573 Self::with_bits(x.to_bits())
574 }
575
576 #[doc = concat!("`", stringify!($float_ty), "`.")]
578 pub fn $as_float(self) -> $float_ty {
579 $float_ty::from_bits(self.bits())
580 }
581 )?
582
583 pub fn abs(self) -> Self {
585 Self::with_bits(self.bits() & !Self::SIGN_MASK)
586 }
587
588 pub fn copysign(self, sign: Self) -> Self {
590 Self::with_bits((self.bits() & !Self::SIGN_MASK) | (sign.bits() & Self::SIGN_MASK))
591 }
592
593 pub fn minimum(self, other: Self) -> Self {
595 if self.is_nan() || other.is_nan() {
597 Self::NAN
598 } else if self.is_zero() && other.is_zero() {
599 if self.is_negative() {
600 self
601 } else {
602 other
603 }
604 } else if self <= other {
605 self
606 } else {
607 other
608 }
609 }
610
611 pub fn maximum(self, other: Self) -> Self {
613 if self.is_nan() || other.is_nan() {
615 Self::NAN
616 } else if self.is_zero() && other.is_zero() {
617 if self.is_positive() {
618 self
619 } else {
620 other
621 }
622 } else if self >= other {
623 self
624 } else {
625 other
626 }
627 }
628
629 #[doc = concat!("`", stringify!($name), "`")]
631 pub fn pow2<I: Into<i32>>(n: I) -> Self {
633 let n = n.into();
634 let w = Self::EXPONENT_BITS;
635 let t = Self::SIGNIFICAND_BITS;
636 let bias = (1 << (w - 1)) - 1;
637 let exponent = n + bias;
638 assert!(exponent > 0, "Underflow n={}", n);
639 assert!(exponent < (1 << w) + 1, "Overflow n={}", n);
640 Self::with_bits((exponent as $bits_ty) << t)
641 }
642
643 #[doc = concat!("`", stringify!($name), "`")]
645 #[doc = concat!("`", stringify!($float_ty), "`")]
647 pub fn fcvt_to_sint_negative_overflow<I: Into<i32>>(n: I) -> Self {
649 let n = n.into();
650 debug_assert!(n < i32::from(Self::BITS));
651 debug_assert!(i32::from(Self::SIGNIFICAND_BITS) + 1 - n < i32::from(Self::BITS));
652 Self::with_bits((1 << (Self::BITS - 1)) | Self::pow2(n - 1).bits() | (1 << (i32::from(Self::SIGNIFICAND_BITS) + 1 - n)))
653 }
654
655 #[doc = concat!("`", stringify!($name), "`,")]
657 pub fn is_nan(self) -> bool {
659 self.abs().bits() > Self::EXPONENT_MASK
660 }
661
662 pub fn is_positive(self) -> bool {
664 !self.is_negative()
665 }
666
667 pub fn is_negative(self) -> bool {
669 self.bits() & Self::SIGN_MASK == Self::SIGN_MASK
670 }
671
672 pub fn is_zero(self) -> bool {
674 self.abs().bits() == 0
675 }
676
677 pub fn non_nan(self) -> Option<Self> {
679 Some(self).filter(|f| !f.is_nan())
680 }
681
682 $(
683 pub fn sqrt(self) -> Self {
685 Self::with_float(Libm::<$float_ty>::sqrt(self.$as_float()))
686 }
687
688 pub fn ceil(self) -> Self {
690 Self::with_float(Libm::<$float_ty>::ceil(self.$as_float()))
691 }
692
693 pub fn floor(self) -> Self {
695 Self::with_float(Libm::<$float_ty>::floor(self.$as_float()))
696 }
697
698 pub fn trunc(self) -> Self {
700 Self::with_float(Libm::<$float_ty>::trunc(self.$as_float()))
701 }
702
703 pub fn round_ties_even(self) -> Self {
706 Self::with_float(Libm::<$float_ty>::roundeven(self.$as_float()))
707 }
708 )?
709 }
710
711 impl PartialOrd for $name {
712 fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
713 $(self.$as_float().partial_cmp(&rhs.$as_float()))?
714 $(
715 ignore!($rust_type_not_stable);
716 if self.is_nan() || rhs.is_nan() {
718 return None;
720 }
721 if self.is_zero() && rhs.is_zero() {
722 return Some(Ordering::Equal);
724 }
725 let lhs_positive = self.is_positive();
726 let rhs_positive = rhs.is_positive();
727 if lhs_positive != rhs_positive {
728 return lhs_positive.partial_cmp(&rhs_positive);
730 }
731 if lhs_positive {
733 self.bits().partial_cmp(&rhs.bits())
734 } else {
735 rhs.bits().partial_cmp(&self.bits())
737 }
738 )?
739 }
740 }
741
742 impl Display for $name {
743 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
744 format_float(u128::from(self.bits()), Self::EXPONENT_BITS, Self::SIGNIFICAND_BITS, f)
745 }
746 }
747
748 impl FromStr for $name {
749 type Err = &'static str;
750
751 fn from_str(s: &str) -> Result<Self, &'static str> {
752 match parse_float(s, Self::EXPONENT_BITS, Self::SIGNIFICAND_BITS) {
753 Ok(b) => Ok(Self::with_bits(b.try_into().unwrap())),
754 Err(s) => Err(s),
755 }
756 }
757 }
758
759 impl IntoBytes for $name {
760 fn into_bytes(self) -> Vec<u8> {
761 self.bits().to_le_bytes().to_vec()
762 }
763 }
764
765 impl Neg for $name {
766 type Output = Self;
767
768 fn neg(self) -> Self {
769 Self::with_bits(self.bits() ^ Self::SIGN_MASK)
770 }
771 }
772
773
774
775 $(
776 impl From<$float_ty> for $name {
777 fn from(x: $float_ty) -> Self {
778 Self::with_float(x)
779 }
780 }
781
782 impl Add for $name {
783 type Output = Self;
784
785 fn add(self, rhs: Self) -> Self {
786 Self::with_float(self.$as_float() + rhs.$as_float())
787 }
788 }
789
790 impl Sub for $name {
791 type Output = Self;
792
793 fn sub(self, rhs: Self) -> Self {
794 Self::with_float(self.$as_float() - rhs.$as_float())
795 }
796 }
797
798 impl Mul for $name {
799 type Output = Self;
800
801 fn mul(self, rhs: Self) -> Self {
802 Self::with_float(self.$as_float() * rhs.$as_float())
803 }
804 }
805
806 impl Div for $name {
807 type Output = Self;
808
809 fn div(self, rhs: Self) -> Self::Output {
810 Self::with_float(self.$as_float() / rhs.$as_float())
811 }
812 }
813 )?
814
815 impl BitAnd for $name {
816 type Output = Self;
817
818 fn bitand(self, rhs: Self) -> Self {
819 Self::with_bits(self.bits() & rhs.bits())
820 }
821 }
822
823 impl BitOr for $name {
824 type Output = Self;
825
826 fn bitor(self, rhs: Self) -> Self {
827 Self::with_bits(self.bits() | rhs.bits())
828 }
829 }
830
831 impl BitXor for $name {
832 type Output = Self;
833
834 fn bitxor(self, rhs: Self) -> Self {
835 Self::with_bits(self.bits() ^ rhs.bits())
836 }
837 }
838
839 impl Not for $name {
840 type Output = Self;
841
842 fn not(self) -> Self {
843 Self::with_bits(!self.bits())
844 }
845 }
846 };
847}
848
849ieee_float! {
850 name = Ieee16,
851 bits = 16,
852 significand_bits = 10,
853 bits_ty = u16,
854 float_ty = f16,
855 rust_type_not_stable = rust_type_not_stable,
856}
857
858impl Ieee16 {
859 pub fn to_f32(self) -> f32 {
861 let bits = u32::from(self.bits());
862 let sign = (bits & 0x8000) << 16;
863 let exponent = (bits >> 10) & 0x1f;
864 let significand = bits & 0x03ff;
865
866 let (f32_exponent, f32_significand) = match exponent {
867 0 if significand == 0 => return f32::from_bits(sign),
868 0 => {
870 let msb = significand.ilog2();
871 ((msb + 103) << 23, (significand - (1 << msb)) << (23 - msb))
872 }
873 0x1f => (0x7f80_0000, (significand << 13) & 0x007f_ffff),
874 _ => ((exponent + 112) << 23, significand << 13),
875 };
876 let quiet = if exponent == 0x1f && f32_significand != 0 {
877 0x0040_0000
878 } else {
879 0
880 };
881 f32::from_bits(sign | f32_exponent | f32_significand | quiet)
882 }
883
884 pub fn from_f32_rne(x: f32) -> Self {
886 let bits = x.to_bits();
887 let sign = ((bits >> 16) & 0x8000) as u16;
888 let exponent = ((bits >> 23) & 0xff) as i32;
889 let significand = bits & 0x007f_ffff;
890
891 match exponent {
892 0xff => Self::infinity_or_nan(sign, significand != 0, (significand >> 13) as u64),
893 0 => Self::with_bits(sign),
895 _ => Self::from_parts(sign, exponent - 127, u64::from(significand | 1 << 23), 23),
896 }
897 }
898
899 pub fn from_f64_rne(x: f64) -> Self {
901 let bits = x.to_bits();
902 let sign = ((bits >> 48) & 0x8000) as u16;
903 let exponent = ((bits >> 52) & 0x7ff) as i32;
904 let significand = bits & 0x000f_ffff_ffff_ffff;
905
906 match exponent {
907 0x7ff => Self::infinity_or_nan(sign, significand != 0, significand >> 42),
908 0 => Self::with_bits(sign),
909 _ => Self::from_parts(sign, exponent - 1023, significand | 1 << 52, 52),
910 }
911 }
912
913 fn infinity_or_nan(sign: u16, is_nan: bool, payload: u64) -> Self {
914 if !is_nan {
915 return Self::with_bits(sign | 0x7c00);
916 }
917 Self::with_bits(sign | 0x7c00 | (payload as u16 & 0x03ff) | 0x0200)
918 }
919
920 fn from_parts(sign: u16, unbiased: i32, significand: u64, significand_bits: u32) -> Self {
922 if unbiased > 15 {
923 return Self::with_bits(sign | 0x7c00);
924 }
925
926 if unbiased >= -14 {
927 let drop = significand_bits - 10;
929 let mut half_significand = ((significand >> drop) & 0x3ff) as u16;
930 let remainder = significand & ((1 << drop) - 1);
931 let halfway = 1 << (drop - 1);
932 let mut half_exponent = (unbiased + 15) as u16;
933 if remainder > halfway || (remainder == halfway && half_significand & 1 == 1) {
934 half_significand += 1;
935 if half_significand == 0x400 {
936 half_significand = 0;
938 half_exponent += 1;
939 if half_exponent >= 0x1f {
940 return Self::with_bits(sign | 0x7c00);
941 }
942 }
943 }
944 return Self::with_bits(sign | (half_exponent << 10) | half_significand);
945 }
946
947 if unbiased < -25 {
948 return Self::with_bits(sign);
949 }
950
951 let shift = (significand_bits as i32 - unbiased - 24) as u32;
953 let mut m = (significand >> shift) as u16;
954 let remainder = significand & ((1 << shift) - 1);
955 let halfway = 1 << (shift - 1);
956 if remainder > halfway || (remainder == halfway && m & 1 == 1) {
957 m += 1;
958 }
959 Self::with_bits(sign | m)
960 }
961}
962
963ieee_float! {
964 name = Ieee32,
965 bits = 32,
966 significand_bits = 23,
967 bits_ty = u32,
968 float_ty = f32,
969 as_float = as_f32,
970}
971
972ieee_float! {
973 name = Ieee64,
974 bits = 64,
975 significand_bits = 52,
976 bits_ty = u64,
977 float_ty = f64,
978 as_float = as_f64,
979}
980
981ieee_float! {
982 name = Ieee128,
983 bits = 128,
984 significand_bits = 112,
985 bits_ty = u128,
986 float_ty = f128,
987 rust_type_not_stable = rust_type_not_stable,
988}
989
990fn format_float(bits: u128, w: u8, t: u8, f: &mut Formatter) -> fmt::Result {
1001 debug_assert!(w > 0 && w <= 16, "Invalid exponent range");
1002 debug_assert!(1 + w + t <= 128, "Too large IEEE format for u128");
1003 debug_assert!((t + w + 1).is_power_of_two(), "Unexpected IEEE format size");
1004
1005 let max_e_bits = (1u128 << w) - 1;
1006 let t_bits = bits & ((1u128 << t) - 1); let e_bits = (bits >> t) & max_e_bits; let sign_bit = (bits >> (w + t)) & 1;
1009
1010 let bias: i32 = (1 << (w - 1)) - 1;
1011 let e = e_bits as i32 - bias; let emin = 1 - bias; let digits = (t + 3) / 4;
1016 let left_t_bits = t_bits << (4 * digits - t);
1018
1019 if sign_bit != 0 {
1021 write!(f, "-")?;
1022 }
1023
1024 if e_bits == 0 {
1025 if t_bits == 0 {
1026 write!(f, "0.0")
1028 } else {
1029 write!(
1031 f,
1032 "0x0.{0:01$x}p{2}",
1033 left_t_bits,
1034 usize::from(digits),
1035 emin
1036 )
1037 }
1038 } else if e_bits == max_e_bits {
1039 if sign_bit == 0 {
1042 write!(f, "+")?;
1043 }
1044 if t_bits == 0 {
1045 write!(f, "Inf")
1047 } else {
1048 let payload = t_bits & ((1 << (t - 1)) - 1);
1050 if t_bits & (1 << (t - 1)) != 0 {
1051 if payload != 0 {
1053 write!(f, "NaN:0x{payload:x}")
1054 } else {
1055 write!(f, "NaN")
1056 }
1057 } else {
1058 write!(f, "sNaN:0x{payload:x}")
1060 }
1061 }
1062 } else {
1063 write!(f, "0x1.{0:01$x}p{2}", left_t_bits, usize::from(digits), e)
1065 }
1066}
1067
1068fn parse_float(s: &str, w: u8, t: u8) -> Result<u128, &'static str> {
1076 debug_assert!(w > 0 && w <= 16, "Invalid exponent range");
1077 debug_assert!(1 + w + t <= 128, "Too large IEEE format for u128");
1078 debug_assert!((t + w + 1).is_power_of_two(), "Unexpected IEEE format size");
1079
1080 let (sign_bit, s2) = if let Some(num) = s.strip_prefix('-') {
1081 (1u128 << (t + w), num)
1082 } else if let Some(num) = s.strip_prefix('+') {
1083 (0, num)
1084 } else {
1085 (0, s)
1086 };
1087
1088 if !s2.starts_with("0x") {
1089 let max_e_bits = ((1u128 << w) - 1) << t;
1090 let quiet_bit = 1u128 << (t - 1);
1091
1092 if s2 == "0.0" {
1094 return Ok(sign_bit);
1095 }
1096
1097 if s2 == "Inf" {
1098 return Ok(sign_bit | max_e_bits);
1100 }
1101 if s2 == "NaN" {
1102 return Ok(sign_bit | max_e_bits | quiet_bit);
1104 }
1105 if let Some(nan) = s2.strip_prefix("NaN:0x") {
1106 return match u128::from_str_radix(nan, 16) {
1108 Ok(payload) if payload < quiet_bit => {
1109 Ok(sign_bit | max_e_bits | quiet_bit | payload)
1110 }
1111 _ => Err("Invalid NaN payload"),
1112 };
1113 }
1114 if let Some(nan) = s2.strip_prefix("sNaN:0x") {
1115 return match u128::from_str_radix(nan, 16) {
1117 Ok(payload) if 0 < payload && payload < quiet_bit => {
1118 Ok(sign_bit | max_e_bits | payload)
1119 }
1120 _ => Err("Invalid sNaN payload"),
1121 };
1122 }
1123
1124 return Err("Float must be hexadecimal");
1125 }
1126 let s3 = &s2[2..];
1127
1128 let mut digits = 0u8;
1129 let mut digits_before_period: Option<u8> = None;
1130 let mut significand = 0u128;
1131 let mut exponent = 0i32;
1132
1133 for (idx, ch) in s3.char_indices() {
1134 match ch {
1135 '.' => {
1136 if digits_before_period != None {
1138 return Err("Multiple radix points");
1139 } else {
1140 digits_before_period = Some(digits);
1141 }
1142 }
1143 'p' => {
1144 let exp_str = &s3[1 + idx..];
1146 match exp_str.parse::<i16>() {
1147 Ok(e) => {
1148 exponent = i32::from(e);
1149 break;
1150 }
1151 Err(_) => return Err("Bad exponent"),
1152 }
1153 }
1154 _ => match ch.to_digit(16) {
1155 Some(digit) => {
1156 digits += 1;
1157 if digits > 32 {
1158 return Err("Too many digits");
1159 }
1160 significand = (significand << 4) | u128::from(digit);
1161 }
1162 None => return Err("Invalid character"),
1163 },
1164 }
1165 }
1166
1167 if digits == 0 {
1168 return Err("No digits");
1169 }
1170
1171 if significand == 0 {
1172 return Ok(sign_bit);
1174 }
1175
1176 match digits_before_period {
1178 None => {} Some(d) => exponent -= 4 * i32::from(digits - d),
1180 };
1181
1182 let significant_bits = (128 - significand.leading_zeros()) as u8;
1184 if significant_bits > t + 1 {
1185 let adjust = significant_bits - (t + 1);
1186 if significand & ((1u128 << adjust) - 1) != 0 {
1187 return Err("Too many significant bits");
1188 }
1189 significand >>= adjust;
1191 exponent += i32::from(adjust);
1192 } else {
1193 let adjust = t + 1 - significant_bits;
1194 significand <<= adjust;
1195 exponent -= i32::from(adjust);
1196 }
1197 debug_assert_eq!(significand >> t, 1);
1198
1199 let t_bits = significand & ((1 << t) - 1);
1201
1202 let max_exp = (1i32 << w) - 2;
1203 let bias: i32 = (1 << (w - 1)) - 1;
1204 exponent += bias + i32::from(t);
1205
1206 if exponent > max_exp {
1207 Err("Magnitude too large")
1208 } else if exponent > 0 {
1209 let e_bits = (exponent as u128) << t;
1211 Ok(sign_bit | e_bits | t_bits)
1212 } else if 1 - exponent <= i32::from(t) {
1213 let adjust = 1 - exponent;
1216 if significand & ((1u128 << adjust) - 1) != 0 {
1217 Err("Subnormal underflow")
1218 } else {
1219 significand >>= adjust;
1220 Ok(sign_bit | significand)
1221 }
1222 } else {
1223 Err("Magnitude too small")
1224 }
1225}
1226
1227#[cfg(test)]
1228mod tests {
1229 use super::*;
1230 use alloc::string::ToString;
1231
1232 #[test]
1233 fn format_imm64() {
1234 assert_eq!(Imm64(0).to_string(), "0");
1235 assert_eq!(Imm64(9999).to_string(), "9999");
1236 assert_eq!(Imm64(10000).to_string(), "0x2710");
1237 assert_eq!(Imm64(-9999).to_string(), "-9999");
1238 assert_eq!(Imm64(-10000).to_string(), "-10000");
1239 assert_eq!(Imm64(0xffff).to_string(), "0xffff");
1240 assert_eq!(Imm64(0x10000).to_string(), "0x0001_0000");
1241 }
1242
1243 #[test]
1244 fn format_uimm64() {
1245 assert_eq!(Uimm64(0).to_string(), "0");
1246 assert_eq!(Uimm64(9999).to_string(), "9999");
1247 assert_eq!(Uimm64(10000).to_string(), "0x2710");
1248 assert_eq!(Uimm64(-9999i64 as u64).to_string(), "0xffff_ffff_ffff_d8f1");
1249 assert_eq!(
1250 Uimm64(-10000i64 as u64).to_string(),
1251 "0xffff_ffff_ffff_d8f0"
1252 );
1253 assert_eq!(Uimm64(0xffff).to_string(), "0xffff");
1254 assert_eq!(Uimm64(0x10000).to_string(), "0x0001_0000");
1255 }
1256
1257 #[track_caller]
1259 fn parse_ok<T: FromStr + Display>(text: &str, want: &str)
1260 where
1261 <T as FromStr>::Err: Display,
1262 {
1263 match text.parse::<T>() {
1264 Err(s) => panic!("\"{text}\".parse() error: {s}"),
1265 Ok(x) => assert_eq!(x.to_string(), want),
1266 }
1267 }
1268
1269 fn parse_err<T: FromStr + Display>(text: &str, msg: &str)
1271 where
1272 <T as FromStr>::Err: Display,
1273 {
1274 match text.parse::<T>() {
1275 Err(s) => assert_eq!(s.to_string(), msg),
1276 Ok(x) => panic!("Wanted Err({msg}), but got {x}"),
1277 }
1278 }
1279
1280 #[test]
1281 fn parse_imm64() {
1282 parse_ok::<Imm64>("0", "0");
1283 parse_ok::<Imm64>("1", "1");
1284 parse_ok::<Imm64>("-0", "0");
1285 parse_ok::<Imm64>("-1", "-1");
1286 parse_ok::<Imm64>("0x0", "0");
1287 parse_ok::<Imm64>("0xf", "15");
1288 parse_ok::<Imm64>("-0x9", "-9");
1289
1290 parse_ok::<Imm64>("0xffffffff_ffffffff", "-1");
1292 parse_ok::<Imm64>("0x80000000_00000000", "-9223372036854775808");
1293 parse_ok::<Imm64>("-0x80000000_00000000", "-9223372036854775808");
1294 parse_err::<Imm64>("-0x80000000_00000001", "Negative number too small");
1295 parse_ok::<Imm64>("18446744073709551615", "-1");
1296 parse_ok::<Imm64>("-9223372036854775808", "-9223372036854775808");
1297 parse_err::<Imm64>("18446744073709551616", "Too large decimal number");
1299 parse_err::<Imm64>("184467440737095516100", "Too large decimal number");
1300 parse_err::<Imm64>("-9223372036854775809", "Negative number too small");
1301
1302 parse_ok::<Imm64>("0_0", "0");
1304 parse_ok::<Imm64>("-_10_0", "-100");
1305 parse_ok::<Imm64>("_10_", "10");
1306 parse_ok::<Imm64>("0x97_88_bb", "0x0097_88bb");
1307 parse_ok::<Imm64>("0x_97_", "151");
1308
1309 parse_err::<Imm64>("", "No digits in number");
1310 parse_err::<Imm64>("-", "No digits in number");
1311 parse_err::<Imm64>("_", "No digits in number");
1312 parse_err::<Imm64>("0x", "No digits in number");
1313 parse_err::<Imm64>("0x_", "No digits in number");
1314 parse_err::<Imm64>("-0x", "No digits in number");
1315 parse_err::<Imm64>(" ", "Invalid character in decimal number");
1316 parse_err::<Imm64>("0 ", "Invalid character in decimal number");
1317 parse_err::<Imm64>(" 0", "Invalid character in decimal number");
1318 parse_err::<Imm64>("--", "Invalid character in decimal number");
1319 parse_err::<Imm64>("-0x-", "Invalid character in hexadecimal number");
1320 parse_err::<Imm64>("abc", "Invalid character in decimal number");
1321 parse_err::<Imm64>("-abc", "Invalid character in decimal number");
1322
1323 parse_err::<Imm64>("0x0_0000_0000_0000_0000", "Too many hexadecimal digits");
1325 }
1326
1327 #[test]
1328 fn parse_uimm64() {
1329 parse_ok::<Uimm64>("0", "0");
1330 parse_ok::<Uimm64>("1", "1");
1331 parse_ok::<Uimm64>("0x0", "0");
1332 parse_ok::<Uimm64>("0xf", "15");
1333 parse_ok::<Uimm64>("0xffffffff_fffffff7", "0xffff_ffff_ffff_fff7");
1334
1335 parse_ok::<Uimm64>("0xffffffff_ffffffff", "0xffff_ffff_ffff_ffff");
1337 parse_ok::<Uimm64>("0x80000000_00000000", "0x8000_0000_0000_0000");
1338 parse_ok::<Uimm64>("18446744073709551615", "0xffff_ffff_ffff_ffff");
1339 parse_err::<Uimm64>("18446744073709551616", "Too large decimal number");
1341 parse_err::<Uimm64>("184467440737095516100", "Too large decimal number");
1342
1343 parse_ok::<Uimm64>("0_0", "0");
1345 parse_ok::<Uimm64>("_10_", "10");
1346 parse_ok::<Uimm64>("0x97_88_bb", "0x0097_88bb");
1347 parse_ok::<Uimm64>("0x_97_", "151");
1348
1349 parse_err::<Uimm64>("", "No digits in number");
1350 parse_err::<Uimm64>("_", "No digits in number");
1351 parse_err::<Uimm64>("0x", "No digits in number");
1352 parse_err::<Uimm64>("0x_", "No digits in number");
1353 parse_err::<Uimm64>("-", "Invalid character in decimal number");
1354 parse_err::<Uimm64>("-0x", "Invalid character in hexadecimal number");
1355 parse_err::<Uimm64>(" ", "Invalid character in decimal number");
1356 parse_err::<Uimm64>("0 ", "Invalid character in decimal number");
1357 parse_err::<Uimm64>(" 0", "Invalid character in decimal number");
1358 parse_err::<Uimm64>("--", "Invalid character in decimal number");
1359 parse_err::<Uimm64>("-0x-", "Invalid character in hexadecimal number");
1360 parse_err::<Uimm64>("-0", "Invalid character in decimal number");
1361 parse_err::<Uimm64>("-1", "Invalid character in decimal number");
1362 parse_err::<Uimm64>("abc", "Invalid character in decimal number");
1363 parse_err::<Uimm64>("-abc", "Invalid character in decimal number");
1364
1365 parse_err::<Uimm64>("0x0_0000_0000_0000_0000", "Too many hexadecimal digits");
1367 }
1368
1369 #[test]
1370 fn format_offset32() {
1371 assert_eq!(Offset32(0).to_string(), "");
1372 assert_eq!(Offset32(1).to_string(), "+1");
1373 assert_eq!(Offset32(-1).to_string(), "-1");
1374 assert_eq!(Offset32(9999).to_string(), "+9999");
1375 assert_eq!(Offset32(10000).to_string(), "+0x2710");
1376 assert_eq!(Offset32(-9999).to_string(), "-9999");
1377 assert_eq!(Offset32(-10000).to_string(), "-0x2710");
1378 assert_eq!(Offset32(0xffff).to_string(), "+0xffff");
1379 assert_eq!(Offset32(0x10000).to_string(), "+0x0001_0000");
1380 }
1381
1382 #[test]
1383 fn parse_offset32() {
1384 parse_ok::<Offset32>("+0", "");
1385 parse_ok::<Offset32>("+1", "+1");
1386 parse_ok::<Offset32>("-0", "");
1387 parse_ok::<Offset32>("-1", "-1");
1388 parse_ok::<Offset32>("+0x0", "");
1389 parse_ok::<Offset32>("+0xf", "+15");
1390 parse_ok::<Offset32>("-0x9", "-9");
1391 parse_ok::<Offset32>("-0x8000_0000", "-0x8000_0000");
1392
1393 parse_err::<Offset32>("+0x8000_0000", "Offset out of range");
1394 }
1395
1396 #[test]
1397 fn format_ieee16() {
1398 assert_eq!(Ieee16::with_bits(0).to_string(), "0.0"); assert_eq!(Ieee16::with_bits(0x8000).to_string(), "-0.0"); assert_eq!(Ieee16::with_bits(0x3c00).to_string(), "0x1.000p0"); assert_eq!(Ieee16::with_bits(0x3e00).to_string(), "0x1.800p0"); assert_eq!(Ieee16::with_bits(0x3800).to_string(), "0x1.000p-1"); assert_eq!(
1404 Ieee16::with_bits(0x1400).to_string(), "0x1.000p-10"
1406 );
1407 assert_eq!(
1408 Ieee16::with_bits(0xfbff).to_string(), "-0x1.ffcp15"
1410 );
1411 assert_eq!(
1412 Ieee16::with_bits(0x7bff).to_string(), "0x1.ffcp15"
1414 );
1415 assert_eq!(
1417 Ieee16::with_bits(0x0400).to_string(), "0x1.000p-14"
1419 );
1420 assert_eq!(
1422 Ieee16::with_bits(0x0200).to_string(), "0x0.800p-14"
1424 );
1425 assert_eq!(
1426 Ieee16::with_bits(0x0001).to_string(), "0x0.004p-14"
1428 );
1429 assert_eq!(
1430 Ieee16::with_bits(0x7c00).to_string(), "+Inf"
1432 );
1433 assert_eq!(
1434 Ieee16::with_bits(0xfc00).to_string(), "-Inf"
1436 );
1437 assert_eq!(
1438 Ieee16::with_bits(0x7e00).to_string(), "+NaN"
1440 );
1441 assert_eq!(
1442 Ieee16::with_bits(0xfe00).to_string(), "-NaN"
1444 );
1445 assert_eq!(Ieee16::with_bits(0x7e01).to_string(), "+NaN:0x1");
1447 assert_eq!(Ieee16::with_bits(0x7f01).to_string(), "+NaN:0x101");
1448 assert_eq!(Ieee16::with_bits(0x7c01).to_string(), "+sNaN:0x1");
1450 assert_eq!(Ieee16::with_bits(0x7d01).to_string(), "+sNaN:0x101");
1451 }
1452
1453 #[test]
1454 fn parse_ieee16() {
1455 parse_ok::<Ieee16>("0.0", "0.0");
1456 parse_ok::<Ieee16>("+0.0", "0.0");
1457 parse_ok::<Ieee16>("-0.0", "-0.0");
1458 parse_ok::<Ieee16>("0x0", "0.0");
1459 parse_ok::<Ieee16>("0x0.0", "0.0");
1460 parse_ok::<Ieee16>("0x.0", "0.0");
1461 parse_ok::<Ieee16>("0x0.", "0.0");
1462 parse_ok::<Ieee16>("0x1", "0x1.000p0");
1463 parse_ok::<Ieee16>("+0x1", "0x1.000p0");
1464 parse_ok::<Ieee16>("-0x1", "-0x1.000p0");
1465 parse_ok::<Ieee16>("0x10", "0x1.000p4");
1466 parse_ok::<Ieee16>("0x10.0", "0x1.000p4");
1467 parse_err::<Ieee16>("0.", "Float must be hexadecimal");
1468 parse_err::<Ieee16>(".0", "Float must be hexadecimal");
1469 parse_err::<Ieee16>("0", "Float must be hexadecimal");
1470 parse_err::<Ieee16>("-0", "Float must be hexadecimal");
1471 parse_err::<Ieee16>(".", "Float must be hexadecimal");
1472 parse_err::<Ieee16>("", "Float must be hexadecimal");
1473 parse_err::<Ieee16>("-", "Float must be hexadecimal");
1474 parse_err::<Ieee16>("0x", "No digits");
1475 parse_err::<Ieee16>("0x..", "Multiple radix points");
1476
1477 parse_ok::<Ieee16>("0x0.ffe", "0x1.ffcp-1");
1479 parse_ok::<Ieee16>("0x1.ffc", "0x1.ffcp0");
1480 parse_ok::<Ieee16>("0x3.ff8", "0x1.ffcp1");
1481 parse_ok::<Ieee16>("0x7.ff", "0x1.ffcp2");
1482 parse_ok::<Ieee16>("0xf.fe", "0x1.ffcp3");
1483 parse_err::<Ieee16>("0x1.ffe", "Too many significant bits");
1484 parse_err::<Ieee16>("0x1.ffc00000000000000000000000000000", "Too many digits");
1485
1486 parse_ok::<Ieee16>("0x1p3", "0x1.000p3");
1488 parse_ok::<Ieee16>("0x1p-3", "0x1.000p-3");
1489 parse_ok::<Ieee16>("0x1.0p3", "0x1.000p3");
1490 parse_ok::<Ieee16>("0x2.0p3", "0x1.000p4");
1491 parse_ok::<Ieee16>("0x1.0p15", "0x1.000p15");
1492 parse_ok::<Ieee16>("0x1.0p-14", "0x1.000p-14");
1493 parse_ok::<Ieee16>("0x0.1p-10", "0x1.000p-14");
1494 parse_err::<Ieee16>("0x2.0p15", "Magnitude too large");
1495
1496 parse_ok::<Ieee16>("0x1.0p-15", "0x0.800p-14");
1498 parse_ok::<Ieee16>("0x1.0p-24", "0x0.004p-14");
1499 parse_ok::<Ieee16>("0x0.004p-14", "0x0.004p-14");
1500 parse_err::<Ieee16>("0x0.102p-14", "Subnormal underflow");
1501 parse_err::<Ieee16>("0x1.8p-24", "Subnormal underflow");
1502 parse_err::<Ieee16>("0x1.0p-25", "Magnitude too small");
1503
1504 parse_ok::<Ieee16>("Inf", "+Inf");
1506 parse_ok::<Ieee16>("+Inf", "+Inf");
1507 parse_ok::<Ieee16>("-Inf", "-Inf");
1508 parse_ok::<Ieee16>("NaN", "+NaN");
1509 parse_ok::<Ieee16>("+NaN", "+NaN");
1510 parse_ok::<Ieee16>("-NaN", "-NaN");
1511 parse_ok::<Ieee16>("NaN:0x0", "+NaN");
1512 parse_err::<Ieee16>("NaN:", "Float must be hexadecimal");
1513 parse_err::<Ieee16>("NaN:0", "Float must be hexadecimal");
1514 parse_err::<Ieee16>("NaN:0x", "Invalid NaN payload");
1515 parse_ok::<Ieee16>("NaN:0x001", "+NaN:0x1");
1516 parse_ok::<Ieee16>("NaN:0x101", "+NaN:0x101");
1517 parse_err::<Ieee16>("NaN:0x301", "Invalid NaN payload");
1518 parse_ok::<Ieee16>("sNaN:0x1", "+sNaN:0x1");
1519 parse_err::<Ieee16>("sNaN:0x0", "Invalid sNaN payload");
1520 parse_ok::<Ieee16>("sNaN:0x101", "+sNaN:0x101");
1521 parse_err::<Ieee16>("sNaN:0x301", "Invalid sNaN payload");
1522 }
1523
1524 #[test]
1525 fn pow2_ieee16() {
1526 assert_eq!(Ieee16::pow2(0).to_string(), "0x1.000p0");
1527 assert_eq!(Ieee16::pow2(1).to_string(), "0x1.000p1");
1528 assert_eq!(Ieee16::pow2(-1).to_string(), "0x1.000p-1");
1529 assert_eq!(Ieee16::pow2(15).to_string(), "0x1.000p15");
1530 assert_eq!(Ieee16::pow2(-14).to_string(), "0x1.000p-14");
1531
1532 assert_eq!((-Ieee16::pow2(1)).to_string(), "-0x1.000p1");
1533 }
1534
1535 #[test]
1536 fn partial_cmp_zero_ieee16() {
1537 let zero = Ieee16::with_bits(0);
1538 let one = Ieee16::pow2(0);
1539 let subnormal = Ieee16::with_bits(1);
1540
1541 for zero in [zero, -zero] {
1542 assert_eq!(zero.partial_cmp(&zero), Some(Ordering::Equal));
1543 assert_eq!(zero.partial_cmp(&-zero), Some(Ordering::Equal));
1544
1545 for (value, ordering) in [
1546 (one, Ordering::Greater),
1547 (-one, Ordering::Less),
1548 (subnormal, Ordering::Greater),
1549 (-subnormal, Ordering::Less),
1550 ] {
1551 assert_eq!(
1552 value.partial_cmp(&zero),
1553 Some(ordering),
1554 "{value} compared with {zero}"
1555 );
1556 assert_eq!(
1557 zero.partial_cmp(&value),
1558 Some(ordering.reverse()),
1559 "{zero} compared with {value}"
1560 );
1561 }
1562 }
1563 }
1564
1565 #[test]
1566 fn fcvt_to_sint_negative_overflow_ieee16() {
1567 let n = 8;
1574 assert_eq!(
1575 "-0x1.020p7",
1576 Ieee16::fcvt_to_sint_negative_overflow(n).to_string()
1577 );
1578 }
1579
1580 #[test]
1582 fn to_f32_known_values_ieee16() {
1583 let cases = [
1584 (0x0000, 0x0000_0000), (0x8000, 0x8000_0000), (0x3c00, 0x3f80_0000), (0xbc00, 0xbf80_0000), (0x7bff, 0x477f_e000), (0x7c00, 0x7f80_0000), (0x0400, 0x3880_0000), (0x0001, 0x3380_0000), (0x03ff, 0x387f_c000), (0x0200, 0x3800_0000), ];
1595 for (input, expected) in cases {
1596 assert_eq!(
1597 Ieee16::with_bits(input).to_f32().to_bits(),
1598 expected,
1599 "bits = {input:#06x}"
1600 );
1601 }
1602 }
1603
1604 #[test]
1606 fn every_tie_rounds_to_even_ieee16() {
1607 for bits in 0..u16::MAX {
1608 let (lo, hi) = (Ieee16::with_bits(bits), Ieee16::with_bits(bits + 1));
1609 if lo.is_nan() || hi.is_nan() || (lo.bits() & 0x7fff) == 0x7bff {
1611 continue;
1612 }
1613 let even = if bits & 1 == 0 { lo } else { hi };
1614
1615 let (a, b) = (lo.to_f32(), hi.to_f32());
1616 let mid = (a + b) / 2.0;
1617 assert_eq!(
1618 Ieee16::from_f32_rne(mid),
1619 even,
1620 "midpoint of {:#06x} and {:#06x}",
1621 bits,
1622 bits + 1
1623 );
1624
1625 if bits < 0x8000 {
1628 let up = f32::from_bits(mid.to_bits() + 1);
1629 let down = f32::from_bits(mid.to_bits() - 1);
1630 assert_eq!(Ieee16::from_f32_rne(up), hi, "{bits:#06x} up");
1631 assert_eq!(Ieee16::from_f32_rne(down), lo, "{bits:#06x} down");
1632 }
1633 }
1634 }
1635
1636 #[test]
1638 fn round_trip_is_identity_ieee16() {
1639 for bits in 0..=u16::MAX {
1640 let original = Ieee16::with_bits(bits);
1641 let back = Ieee16::from_f32_rne(original.to_f32());
1642 let expected = if original.is_nan() {
1643 Ieee16::with_bits(bits | 0x0200)
1644 } else {
1645 original
1646 };
1647 assert_eq!(back, expected, "bits = {bits:#06x}");
1648 }
1649 }
1650
1651 #[test]
1653 fn from_f64_rne_agrees_ieee16() {
1654 for bits in 0..u16::MAX {
1655 let value = Ieee16::with_bits(bits);
1656 if value.is_nan() {
1657 continue;
1658 }
1659 let as_f64 = f64::from(value.to_f32());
1660 assert_eq!(
1661 Ieee16::from_f64_rne(as_f64),
1662 Ieee16::from_f32_rne(value.to_f32()),
1663 "bits = {bits:#06x}"
1664 );
1665 }
1666 }
1667
1668 #[test]
1671 fn fma_does_not_double_round_ieee16() {
1672 let (x, y, z) = (
1673 f64::from(Ieee16::with_bits(0x520b).to_f32()),
1674 f64::from(Ieee16::with_bits(0x00e9).to_f32()),
1675 f64::from(Ieee16::with_bits(0x2ff6).to_f32()),
1676 );
1677 let exact = x * y + z;
1680 assert_eq!(Ieee16::from_f64_rne(exact).bits(), 0x3001);
1681 assert_eq!(Ieee16::from_f32_rne(exact as f32).bits(), 0x3000);
1682 }
1683
1684 #[test]
1687 fn subnormal_source_rounds_to_zero_ieee16() {
1688 for bits in [0x0000_0001, 0x003f_ffff, 0x007f_ffff, 0x807f_ffff] {
1689 let x = f32::from_bits(bits);
1690 let expected = if bits >> 31 == 1 { 0x8000 } else { 0x0000 };
1691 assert_eq!(
1692 Ieee16::from_f32_rne(x).bits(),
1693 expected,
1694 "bits = {bits:#010x}"
1695 );
1696 }
1697 for bits in [
1698 0x0000_0000_0000_0001,
1699 0x000f_ffff_ffff_ffff,
1700 0x800f_ffff_ffff_ffff,
1701 ] {
1702 let x = f64::from_bits(bits);
1703 let expected = if bits >> 63 == 1 { 0x8000 } else { 0x0000 };
1704 assert_eq!(
1705 Ieee16::from_f64_rne(x).bits(),
1706 expected,
1707 "bits = {bits:#018x}"
1708 );
1709 }
1710 assert_eq!(Ieee16::from_f32_rne(0.0).bits(), 0x0000);
1712 assert_eq!(Ieee16::from_f32_rne(-0.0).bits(), 0x8000);
1713 assert_eq!(Ieee16::from_f64_rne(0.0).bits(), 0x0000);
1714 assert_eq!(Ieee16::from_f64_rne(-0.0).bits(), 0x8000);
1715 }
1716
1717 #[test]
1719 fn f64_narrowing_does_not_double_round_ieee16() {
1720 let just_past = 1.0 + 2f64.powi(-11) + 2f64.powi(-40);
1721 assert_eq!(Ieee16::from_f64_rne(just_past).bits(), 0x3c01);
1722 assert_eq!(Ieee16::from_f64_rne(-just_past).bits(), 0xbc01);
1723 assert_eq!(Ieee16::from_f32_rne(just_past as f32).bits(), 0x3c00);
1724 }
1725
1726 #[test]
1727 fn overflow_boundaries_ieee16() {
1728 assert_eq!(Ieee16::from_f32_rne(65504.0).bits(), 0x7bff);
1729 assert_eq!(Ieee16::from_f32_rne(65519.0).bits(), 0x7bff);
1730 assert_eq!(Ieee16::from_f32_rne(65520.0).bits(), 0x7c00);
1732 assert_eq!(Ieee16::from_f32_rne(65536.0).bits(), 0x7c00);
1733 assert_eq!(Ieee16::from_f32_rne(f32::INFINITY).bits(), 0x7c00);
1734 assert_eq!(Ieee16::from_f32_rne(-f32::INFINITY).bits(), 0xfc00);
1735 assert_eq!(Ieee16::from_f32_rne(1e30).bits(), 0x7c00);
1736 }
1737
1738 #[test]
1739 fn underflow_boundaries_ieee16() {
1740 assert_eq!(Ieee16::from_f32_rne(2f32.powi(-14)).bits(), 0x0400);
1741 assert_eq!(Ieee16::from_f32_rne(2f32.powi(-15)).bits(), 0x0200);
1742 assert_eq!(Ieee16::from_f32_rne(2f32.powi(-24)).bits(), 0x0001);
1743 assert_eq!(Ieee16::from_f32_rne(2f32.powi(-25)).bits(), 0x0000);
1745 assert_eq!(Ieee16::from_f32_rne(2f32.powi(-26)).bits(), 0x0000);
1746 assert_eq!(Ieee16::from_f32_rne(0.0).bits(), 0x0000);
1747 assert_eq!(Ieee16::from_f32_rne(-0.0).bits(), 0x8000);
1748 }
1749
1750 #[test]
1751 fn subnormal_rounds_up_to_smallest_normal_ieee16() {
1752 assert_eq!(
1753 Ieee16::from_f32_rne(Ieee16::with_bits(0x03ff).to_f32()).bits(),
1754 0x03ff
1755 );
1756 assert_eq!(
1759 Ieee16::from_f32_rne(f32::from_bits(0x387f_e000)).bits(),
1760 0x0400
1761 );
1762 }
1763
1764 #[test]
1765 fn nan_is_quieted_ieee16() {
1766 for input in [f32::NAN, -f32::NAN, f32::from_bits(0x7f80_0001)] {
1767 let out = Ieee16::from_f32_rne(input);
1768 assert!(out.is_nan(), "input = {input:e}");
1769 }
1770 }
1771
1772 #[test]
1773 fn format_ieee32() {
1774 assert_eq!(Ieee32::with_float(0.0).to_string(), "0.0");
1775 assert_eq!(Ieee32::with_float(-0.0).to_string(), "-0.0");
1776 assert_eq!(Ieee32::with_float(1.0).to_string(), "0x1.000000p0");
1777 assert_eq!(Ieee32::with_float(1.5).to_string(), "0x1.800000p0");
1778 assert_eq!(Ieee32::with_float(0.5).to_string(), "0x1.000000p-1");
1779 assert_eq!(
1780 Ieee32::with_float(f32::EPSILON).to_string(),
1781 "0x1.000000p-23"
1782 );
1783 assert_eq!(Ieee32::with_float(f32::MIN).to_string(), "-0x1.fffffep127");
1784 assert_eq!(Ieee32::with_float(f32::MAX).to_string(), "0x1.fffffep127");
1785 assert_eq!(
1787 Ieee32::with_float(f32::MIN_POSITIVE).to_string(),
1788 "0x1.000000p-126"
1789 );
1790 assert_eq!(
1792 Ieee32::with_float(f32::MIN_POSITIVE / 2.0).to_string(),
1793 "0x0.800000p-126"
1794 );
1795 assert_eq!(
1796 Ieee32::with_float(f32::MIN_POSITIVE * f32::EPSILON).to_string(),
1797 "0x0.000002p-126"
1798 );
1799 assert_eq!(Ieee32::with_float(f32::INFINITY).to_string(), "+Inf");
1800 assert_eq!(Ieee32::with_float(f32::NEG_INFINITY).to_string(), "-Inf");
1801 assert_eq!(Ieee32::with_float(f32::NAN).to_string(), "+NaN");
1802 assert_eq!(Ieee32::with_float(-f32::NAN).to_string(), "-NaN");
1803 assert_eq!(Ieee32::with_bits(0x7fc00001).to_string(), "+NaN:0x1");
1805 assert_eq!(Ieee32::with_bits(0x7ff00001).to_string(), "+NaN:0x300001");
1806 assert_eq!(Ieee32::with_bits(0x7f800001).to_string(), "+sNaN:0x1");
1808 assert_eq!(Ieee32::with_bits(0x7fa00001).to_string(), "+sNaN:0x200001");
1809 }
1810
1811 #[test]
1812 fn parse_ieee32() {
1813 parse_ok::<Ieee32>("0.0", "0.0");
1814 parse_ok::<Ieee32>("+0.0", "0.0");
1815 parse_ok::<Ieee32>("-0.0", "-0.0");
1816 parse_ok::<Ieee32>("0x0", "0.0");
1817 parse_ok::<Ieee32>("0x0.0", "0.0");
1818 parse_ok::<Ieee32>("0x.0", "0.0");
1819 parse_ok::<Ieee32>("0x0.", "0.0");
1820 parse_ok::<Ieee32>("0x1", "0x1.000000p0");
1821 parse_ok::<Ieee32>("+0x1", "0x1.000000p0");
1822 parse_ok::<Ieee32>("-0x1", "-0x1.000000p0");
1823 parse_ok::<Ieee32>("0x10", "0x1.000000p4");
1824 parse_ok::<Ieee32>("0x10.0", "0x1.000000p4");
1825 parse_err::<Ieee32>("0.", "Float must be hexadecimal");
1826 parse_err::<Ieee32>(".0", "Float must be hexadecimal");
1827 parse_err::<Ieee32>("0", "Float must be hexadecimal");
1828 parse_err::<Ieee32>("-0", "Float must be hexadecimal");
1829 parse_err::<Ieee32>(".", "Float must be hexadecimal");
1830 parse_err::<Ieee32>("", "Float must be hexadecimal");
1831 parse_err::<Ieee32>("-", "Float must be hexadecimal");
1832 parse_err::<Ieee32>("0x", "No digits");
1833 parse_err::<Ieee32>("0x..", "Multiple radix points");
1834
1835 parse_ok::<Ieee32>("0x0.ffffff", "0x1.fffffep-1");
1837 parse_ok::<Ieee32>("0x1.fffffe", "0x1.fffffep0");
1838 parse_ok::<Ieee32>("0x3.fffffc", "0x1.fffffep1");
1839 parse_ok::<Ieee32>("0x7.fffff8", "0x1.fffffep2");
1840 parse_ok::<Ieee32>("0xf.fffff0", "0x1.fffffep3");
1841 parse_err::<Ieee32>("0x1.ffffff", "Too many significant bits");
1842 parse_err::<Ieee32>("0x1.fffffe00000000000000000000000000", "Too many digits");
1843
1844 parse_ok::<Ieee32>("0x1p3", "0x1.000000p3");
1846 parse_ok::<Ieee32>("0x1p-3", "0x1.000000p-3");
1847 parse_ok::<Ieee32>("0x1.0p3", "0x1.000000p3");
1848 parse_ok::<Ieee32>("0x2.0p3", "0x1.000000p4");
1849 parse_ok::<Ieee32>("0x1.0p127", "0x1.000000p127");
1850 parse_ok::<Ieee32>("0x1.0p-126", "0x1.000000p-126");
1851 parse_ok::<Ieee32>("0x0.1p-122", "0x1.000000p-126");
1852 parse_err::<Ieee32>("0x2.0p127", "Magnitude too large");
1853
1854 parse_ok::<Ieee32>("0x1.0p-127", "0x0.800000p-126");
1856 parse_ok::<Ieee32>("0x1.0p-149", "0x0.000002p-126");
1857 parse_ok::<Ieee32>("0x0.000002p-126", "0x0.000002p-126");
1858 parse_err::<Ieee32>("0x0.100001p-126", "Subnormal underflow");
1859 parse_err::<Ieee32>("0x1.8p-149", "Subnormal underflow");
1860 parse_err::<Ieee32>("0x1.0p-150", "Magnitude too small");
1861
1862 parse_ok::<Ieee32>("Inf", "+Inf");
1864 parse_ok::<Ieee32>("+Inf", "+Inf");
1865 parse_ok::<Ieee32>("-Inf", "-Inf");
1866 parse_ok::<Ieee32>("NaN", "+NaN");
1867 parse_ok::<Ieee32>("+NaN", "+NaN");
1868 parse_ok::<Ieee32>("-NaN", "-NaN");
1869 parse_ok::<Ieee32>("NaN:0x0", "+NaN");
1870 parse_err::<Ieee32>("NaN:", "Float must be hexadecimal");
1871 parse_err::<Ieee32>("NaN:0", "Float must be hexadecimal");
1872 parse_err::<Ieee32>("NaN:0x", "Invalid NaN payload");
1873 parse_ok::<Ieee32>("NaN:0x000001", "+NaN:0x1");
1874 parse_ok::<Ieee32>("NaN:0x300001", "+NaN:0x300001");
1875 parse_err::<Ieee32>("NaN:0x400001", "Invalid NaN payload");
1876 parse_ok::<Ieee32>("sNaN:0x1", "+sNaN:0x1");
1877 parse_err::<Ieee32>("sNaN:0x0", "Invalid sNaN payload");
1878 parse_ok::<Ieee32>("sNaN:0x200001", "+sNaN:0x200001");
1879 parse_err::<Ieee32>("sNaN:0x400001", "Invalid sNaN payload");
1880 }
1881
1882 #[test]
1883 fn pow2_ieee32() {
1884 assert_eq!(Ieee32::pow2(0).to_string(), "0x1.000000p0");
1885 assert_eq!(Ieee32::pow2(1).to_string(), "0x1.000000p1");
1886 assert_eq!(Ieee32::pow2(-1).to_string(), "0x1.000000p-1");
1887 assert_eq!(Ieee32::pow2(127).to_string(), "0x1.000000p127");
1888 assert_eq!(Ieee32::pow2(-126).to_string(), "0x1.000000p-126");
1889
1890 assert_eq!((-Ieee32::pow2(1)).to_string(), "-0x1.000000p1");
1891 }
1892
1893 #[test]
1894 fn fcvt_to_sint_negative_overflow_ieee32() {
1895 for n in [8, 16] {
1896 assert_eq!(
1897 -((1u32 << (n - 1)) as f32) - 1.0,
1898 Ieee32::fcvt_to_sint_negative_overflow(n).as_f32(),
1899 "n = {n}"
1900 );
1901 }
1902 }
1903
1904 #[test]
1905 fn format_ieee64() {
1906 assert_eq!(Ieee64::with_float(0.0).to_string(), "0.0");
1907 assert_eq!(Ieee64::with_float(-0.0).to_string(), "-0.0");
1908 assert_eq!(Ieee64::with_float(1.0).to_string(), "0x1.0000000000000p0");
1909 assert_eq!(Ieee64::with_float(1.5).to_string(), "0x1.8000000000000p0");
1910 assert_eq!(Ieee64::with_float(0.5).to_string(), "0x1.0000000000000p-1");
1911 assert_eq!(
1912 Ieee64::with_float(f64::EPSILON).to_string(),
1913 "0x1.0000000000000p-52"
1914 );
1915 assert_eq!(
1916 Ieee64::with_float(f64::MIN).to_string(),
1917 "-0x1.fffffffffffffp1023"
1918 );
1919 assert_eq!(
1920 Ieee64::with_float(f64::MAX).to_string(),
1921 "0x1.fffffffffffffp1023"
1922 );
1923 assert_eq!(
1925 Ieee64::with_float(f64::MIN_POSITIVE).to_string(),
1926 "0x1.0000000000000p-1022"
1927 );
1928 assert_eq!(
1930 Ieee64::with_float(f64::MIN_POSITIVE / 2.0).to_string(),
1931 "0x0.8000000000000p-1022"
1932 );
1933 assert_eq!(
1934 Ieee64::with_float(f64::MIN_POSITIVE * f64::EPSILON).to_string(),
1935 "0x0.0000000000001p-1022"
1936 );
1937 assert_eq!(Ieee64::with_float(f64::INFINITY).to_string(), "+Inf");
1938 assert_eq!(Ieee64::with_float(f64::NEG_INFINITY).to_string(), "-Inf");
1939 assert_eq!(Ieee64::with_float(f64::NAN).to_string(), "+NaN");
1940 assert_eq!(Ieee64::with_float(-f64::NAN).to_string(), "-NaN");
1941 assert_eq!(
1943 Ieee64::with_bits(0x7ff8000000000001).to_string(),
1944 "+NaN:0x1"
1945 );
1946 assert_eq!(
1947 Ieee64::with_bits(0x7ffc000000000001).to_string(),
1948 "+NaN:0x4000000000001"
1949 );
1950 assert_eq!(
1952 Ieee64::with_bits(0x7ff0000000000001).to_string(),
1953 "+sNaN:0x1"
1954 );
1955 assert_eq!(
1956 Ieee64::with_bits(0x7ff4000000000001).to_string(),
1957 "+sNaN:0x4000000000001"
1958 );
1959 }
1960
1961 #[test]
1962 fn parse_ieee64() {
1963 parse_ok::<Ieee64>("0.0", "0.0");
1964 parse_ok::<Ieee64>("-0.0", "-0.0");
1965 parse_ok::<Ieee64>("0x0", "0.0");
1966 parse_ok::<Ieee64>("0x0.0", "0.0");
1967 parse_ok::<Ieee64>("0x.0", "0.0");
1968 parse_ok::<Ieee64>("0x0.", "0.0");
1969 parse_ok::<Ieee64>("0x1", "0x1.0000000000000p0");
1970 parse_ok::<Ieee64>("-0x1", "-0x1.0000000000000p0");
1971 parse_ok::<Ieee64>("0x10", "0x1.0000000000000p4");
1972 parse_ok::<Ieee64>("0x10.0", "0x1.0000000000000p4");
1973 parse_err::<Ieee64>("0.", "Float must be hexadecimal");
1974 parse_err::<Ieee64>(".0", "Float must be hexadecimal");
1975 parse_err::<Ieee64>("0", "Float must be hexadecimal");
1976 parse_err::<Ieee64>("-0", "Float must be hexadecimal");
1977 parse_err::<Ieee64>(".", "Float must be hexadecimal");
1978 parse_err::<Ieee64>("", "Float must be hexadecimal");
1979 parse_err::<Ieee64>("-", "Float must be hexadecimal");
1980 parse_err::<Ieee64>("0x", "No digits");
1981 parse_err::<Ieee64>("0x..", "Multiple radix points");
1982
1983 parse_ok::<Ieee64>("0x0.fffffffffffff8", "0x1.fffffffffffffp-1");
1985 parse_ok::<Ieee64>("0x1.fffffffffffff", "0x1.fffffffffffffp0");
1986 parse_ok::<Ieee64>("0x3.ffffffffffffe", "0x1.fffffffffffffp1");
1987 parse_ok::<Ieee64>("0x7.ffffffffffffc", "0x1.fffffffffffffp2");
1988 parse_ok::<Ieee64>("0xf.ffffffffffff8", "0x1.fffffffffffffp3");
1989 parse_err::<Ieee64>("0x3.fffffffffffff", "Too many significant bits");
1990 parse_err::<Ieee64>("0x001.fffffe000000000000000000000000", "Too many digits");
1991
1992 parse_ok::<Ieee64>("0x1p3", "0x1.0000000000000p3");
1994 parse_ok::<Ieee64>("0x1p-3", "0x1.0000000000000p-3");
1995 parse_ok::<Ieee64>("0x1.0p3", "0x1.0000000000000p3");
1996 parse_ok::<Ieee64>("0x2.0p3", "0x1.0000000000000p4");
1997 parse_ok::<Ieee64>("0x1.0p1023", "0x1.0000000000000p1023");
1998 parse_ok::<Ieee64>("0x1.0p-1022", "0x1.0000000000000p-1022");
1999 parse_ok::<Ieee64>("0x0.1p-1018", "0x1.0000000000000p-1022");
2000 parse_err::<Ieee64>("0x2.0p1023", "Magnitude too large");
2001
2002 parse_ok::<Ieee64>("0x1.0p-1023", "0x0.8000000000000p-1022");
2004 parse_ok::<Ieee64>("0x1.0p-1074", "0x0.0000000000001p-1022");
2005 parse_ok::<Ieee64>("0x0.0000000000001p-1022", "0x0.0000000000001p-1022");
2006 parse_err::<Ieee64>("0x0.10000000000008p-1022", "Subnormal underflow");
2007 parse_err::<Ieee64>("0x1.8p-1074", "Subnormal underflow");
2008 parse_err::<Ieee64>("0x1.0p-1075", "Magnitude too small");
2009
2010 parse_ok::<Ieee64>("Inf", "+Inf");
2012 parse_ok::<Ieee64>("-Inf", "-Inf");
2013 parse_ok::<Ieee64>("NaN", "+NaN");
2014 parse_ok::<Ieee64>("-NaN", "-NaN");
2015 parse_ok::<Ieee64>("NaN:0x0", "+NaN");
2016 parse_err::<Ieee64>("NaN:", "Float must be hexadecimal");
2017 parse_err::<Ieee64>("NaN:0", "Float must be hexadecimal");
2018 parse_err::<Ieee64>("NaN:0x", "Invalid NaN payload");
2019 parse_ok::<Ieee64>("NaN:0x000001", "+NaN:0x1");
2020 parse_ok::<Ieee64>("NaN:0x4000000000001", "+NaN:0x4000000000001");
2021 parse_err::<Ieee64>("NaN:0x8000000000001", "Invalid NaN payload");
2022 parse_ok::<Ieee64>("sNaN:0x1", "+sNaN:0x1");
2023 parse_err::<Ieee64>("sNaN:0x0", "Invalid sNaN payload");
2024 parse_ok::<Ieee64>("sNaN:0x4000000000001", "+sNaN:0x4000000000001");
2025 parse_err::<Ieee64>("sNaN:0x8000000000001", "Invalid sNaN payload");
2026 }
2027
2028 #[test]
2029 fn pow2_ieee64() {
2030 assert_eq!(Ieee64::pow2(0).to_string(), "0x1.0000000000000p0");
2031 assert_eq!(Ieee64::pow2(1).to_string(), "0x1.0000000000000p1");
2032 assert_eq!(Ieee64::pow2(-1).to_string(), "0x1.0000000000000p-1");
2033 assert_eq!(Ieee64::pow2(1023).to_string(), "0x1.0000000000000p1023");
2034 assert_eq!(Ieee64::pow2(-1022).to_string(), "0x1.0000000000000p-1022");
2035
2036 assert_eq!((-Ieee64::pow2(1)).to_string(), "-0x1.0000000000000p1");
2037 }
2038
2039 #[test]
2040 fn fcvt_to_sint_negative_overflow_ieee64() {
2041 for n in [8, 16, 32] {
2042 assert_eq!(
2043 -((1u64 << (n - 1)) as f64) - 1.0,
2044 Ieee64::fcvt_to_sint_negative_overflow(n).as_f64(),
2045 "n = {n}"
2046 );
2047 }
2048 }
2049
2050 #[test]
2051 fn format_ieee128() {
2052 assert_eq!(
2053 Ieee128::with_bits(0x00000000000000000000000000000000).to_string(), "0.0"
2055 );
2056 assert_eq!(
2057 Ieee128::with_bits(0x80000000000000000000000000000000).to_string(), "-0.0"
2059 );
2060 assert_eq!(
2061 Ieee128::with_bits(0x3fff0000000000000000000000000000).to_string(), "0x1.0000000000000000000000000000p0"
2063 );
2064 assert_eq!(
2065 Ieee128::with_bits(0x3fff8000000000000000000000000000).to_string(), "0x1.8000000000000000000000000000p0"
2067 );
2068 assert_eq!(
2069 Ieee128::with_bits(0x3ffe0000000000000000000000000000).to_string(), "0x1.0000000000000000000000000000p-1"
2071 );
2072 assert_eq!(
2073 Ieee128::with_bits(0x3f8f0000000000000000000000000000).to_string(), "0x1.0000000000000000000000000000p-112"
2075 );
2076 assert_eq!(
2077 Ieee128::with_bits(0xfffeffffffffffffffffffffffffffff).to_string(), "-0x1.ffffffffffffffffffffffffffffp16383"
2079 );
2080 assert_eq!(
2081 Ieee128::with_bits(0x7ffeffffffffffffffffffffffffffff).to_string(), "0x1.ffffffffffffffffffffffffffffp16383"
2083 );
2084 assert_eq!(
2086 Ieee128::with_bits(0x00010000000000000000000000000000).to_string(), "0x1.0000000000000000000000000000p-16382"
2088 );
2089 assert_eq!(
2091 Ieee128::with_bits(0x00008000000000000000000000000000).to_string(), "0x0.8000000000000000000000000000p-16382"
2093 );
2094 assert_eq!(
2095 Ieee128::with_bits(0x00000000000000000000000000000001).to_string(), "0x0.0000000000000000000000000001p-16382"
2097 );
2098 assert_eq!(
2099 Ieee128::with_bits(0x7fff0000000000000000000000000000).to_string(), "+Inf"
2101 );
2102 assert_eq!(
2103 Ieee128::with_bits(0xffff0000000000000000000000000000).to_string(), "-Inf"
2105 );
2106 assert_eq!(
2107 Ieee128::with_bits(0x7fff8000000000000000000000000000).to_string(), "+NaN"
2109 );
2110 assert_eq!(
2111 Ieee128::with_bits(0xffff8000000000000000000000000000).to_string(), "-NaN"
2113 );
2114 assert_eq!(
2116 Ieee128::with_bits(0x7fff8000000000000000000000000001).to_string(),
2117 "+NaN:0x1"
2118 );
2119 assert_eq!(
2120 Ieee128::with_bits(0x7fffc000000000000000000000000001).to_string(),
2121 "+NaN:0x4000000000000000000000000001"
2122 );
2123 assert_eq!(
2125 Ieee128::with_bits(0x7fff0000000000000000000000000001).to_string(),
2126 "+sNaN:0x1"
2127 );
2128 assert_eq!(
2129 Ieee128::with_bits(0x7fff4000000000000000000000000001).to_string(),
2130 "+sNaN:0x4000000000000000000000000001"
2131 );
2132 }
2133
2134 #[test]
2135 fn parse_ieee128() {
2136 parse_ok::<Ieee128>("0.0", "0.0");
2137 parse_ok::<Ieee128>("-0.0", "-0.0");
2138 parse_ok::<Ieee128>("0x0", "0.0");
2139 parse_ok::<Ieee128>("0x0.0", "0.0");
2140 parse_ok::<Ieee128>("0x.0", "0.0");
2141 parse_ok::<Ieee128>("0x0.", "0.0");
2142 parse_ok::<Ieee128>("0x1", "0x1.0000000000000000000000000000p0");
2143 parse_ok::<Ieee128>("-0x1", "-0x1.0000000000000000000000000000p0");
2144 parse_ok::<Ieee128>("0x10", "0x1.0000000000000000000000000000p4");
2145 parse_ok::<Ieee128>("0x10.0", "0x1.0000000000000000000000000000p4");
2146 parse_err::<Ieee128>("0.", "Float must be hexadecimal");
2147 parse_err::<Ieee128>(".0", "Float must be hexadecimal");
2148 parse_err::<Ieee128>("0", "Float must be hexadecimal");
2149 parse_err::<Ieee128>("-0", "Float must be hexadecimal");
2150 parse_err::<Ieee128>(".", "Float must be hexadecimal");
2151 parse_err::<Ieee128>("", "Float must be hexadecimal");
2152 parse_err::<Ieee128>("-", "Float must be hexadecimal");
2153 parse_err::<Ieee128>("0x", "No digits");
2154 parse_err::<Ieee128>("0x..", "Multiple radix points");
2155
2156 parse_ok::<Ieee128>(
2158 "0x0.ffffffffffffffffffffffffffff8",
2159 "0x1.ffffffffffffffffffffffffffffp-1",
2160 );
2161 parse_ok::<Ieee128>(
2162 "0x1.ffffffffffffffffffffffffffff",
2163 "0x1.ffffffffffffffffffffffffffffp0",
2164 );
2165 parse_ok::<Ieee128>(
2166 "0x3.fffffffffffffffffffffffffffe",
2167 "0x1.ffffffffffffffffffffffffffffp1",
2168 );
2169 parse_ok::<Ieee128>(
2170 "0x7.fffffffffffffffffffffffffffc",
2171 "0x1.ffffffffffffffffffffffffffffp2",
2172 );
2173 parse_ok::<Ieee128>(
2174 "0xf.fffffffffffffffffffffffffff8",
2175 "0x1.ffffffffffffffffffffffffffffp3",
2176 );
2177 parse_err::<Ieee128>(
2178 "0x3.ffffffffffffffffffffffffffff",
2179 "Too many significant bits",
2180 );
2181 parse_err::<Ieee128>("0x001.fffffe000000000000000000000000", "Too many digits");
2182
2183 parse_ok::<Ieee128>("0x1p3", "0x1.0000000000000000000000000000p3");
2185 parse_ok::<Ieee128>("0x1p-3", "0x1.0000000000000000000000000000p-3");
2186 parse_ok::<Ieee128>("0x1.0p3", "0x1.0000000000000000000000000000p3");
2187 parse_ok::<Ieee128>("0x2.0p3", "0x1.0000000000000000000000000000p4");
2188 parse_ok::<Ieee128>("0x1.0p16383", "0x1.0000000000000000000000000000p16383");
2189 parse_ok::<Ieee128>("0x1.0p-16382", "0x1.0000000000000000000000000000p-16382");
2190 parse_ok::<Ieee128>("0x0.1p-16378", "0x1.0000000000000000000000000000p-16382");
2191 parse_err::<Ieee128>("0x2.0p16383", "Magnitude too large");
2192
2193 parse_ok::<Ieee128>("0x1.0p-16383", "0x0.8000000000000000000000000000p-16382");
2195 parse_ok::<Ieee128>("0x1.0p-16494", "0x0.0000000000000000000000000001p-16382");
2196 parse_ok::<Ieee128>(
2197 "0x0.0000000000000000000000000001p-16382",
2198 "0x0.0000000000000000000000000001p-16382",
2199 );
2200 parse_err::<Ieee128>(
2201 "0x0.10000000000000000000000000008p-16382",
2202 "Subnormal underflow",
2203 );
2204 parse_err::<Ieee128>("0x1.8p-16494", "Subnormal underflow");
2205 parse_err::<Ieee128>("0x1.0p-16495", "Magnitude too small");
2206
2207 parse_ok::<Ieee128>("Inf", "+Inf");
2209 parse_ok::<Ieee128>("-Inf", "-Inf");
2210 parse_ok::<Ieee128>("NaN", "+NaN");
2211 parse_ok::<Ieee128>("-NaN", "-NaN");
2212 parse_ok::<Ieee128>("NaN:0x0", "+NaN");
2213 parse_err::<Ieee128>("NaN:", "Float must be hexadecimal");
2214 parse_err::<Ieee128>("NaN:0", "Float must be hexadecimal");
2215 parse_err::<Ieee128>("NaN:0x", "Invalid NaN payload");
2216 parse_ok::<Ieee128>("NaN:0x000001", "+NaN:0x1");
2217 parse_ok::<Ieee128>(
2218 "NaN:0x4000000000000000000000000001",
2219 "+NaN:0x4000000000000000000000000001",
2220 );
2221 parse_err::<Ieee128>("NaN:0x8000000000000000000000000001", "Invalid NaN payload");
2222 parse_ok::<Ieee128>("sNaN:0x1", "+sNaN:0x1");
2223 parse_err::<Ieee128>("sNaN:0x0", "Invalid sNaN payload");
2224 parse_ok::<Ieee128>(
2225 "sNaN:0x4000000000000000000000000001",
2226 "+sNaN:0x4000000000000000000000000001",
2227 );
2228 parse_err::<Ieee128>(
2229 "sNaN:0x8000000000000000000000000001",
2230 "Invalid sNaN payload",
2231 );
2232 }
2233
2234 #[test]
2235 fn pow2_ieee128() {
2236 assert_eq!(
2237 Ieee128::pow2(0).to_string(),
2238 "0x1.0000000000000000000000000000p0"
2239 );
2240 assert_eq!(
2241 Ieee128::pow2(1).to_string(),
2242 "0x1.0000000000000000000000000000p1"
2243 );
2244 assert_eq!(
2245 Ieee128::pow2(-1).to_string(),
2246 "0x1.0000000000000000000000000000p-1"
2247 );
2248 assert_eq!(
2249 Ieee128::pow2(16383).to_string(),
2250 "0x1.0000000000000000000000000000p16383"
2251 );
2252 assert_eq!(
2253 Ieee128::pow2(-16382).to_string(),
2254 "0x1.0000000000000000000000000000p-16382"
2255 );
2256
2257 assert_eq!(
2258 (-Ieee128::pow2(1)).to_string(),
2259 "-0x1.0000000000000000000000000000p1"
2260 );
2261 }
2262
2263 #[test]
2264 fn partial_cmp_zero_ieee128() {
2265 let zero = Ieee128::with_bits(0);
2266 let one = Ieee128::pow2(0);
2267 let subnormal = Ieee128::with_bits(1);
2268
2269 for zero in [zero, -zero] {
2270 assert_eq!(zero.partial_cmp(&zero), Some(Ordering::Equal));
2271 assert_eq!(zero.partial_cmp(&-zero), Some(Ordering::Equal));
2272
2273 for (value, ordering) in [
2274 (one, Ordering::Greater),
2275 (-one, Ordering::Less),
2276 (subnormal, Ordering::Greater),
2277 (-subnormal, Ordering::Less),
2278 ] {
2279 assert_eq!(
2280 value.partial_cmp(&zero),
2281 Some(ordering),
2282 "{value} compared with {zero}"
2283 );
2284 assert_eq!(
2285 zero.partial_cmp(&value),
2286 Some(ordering.reverse()),
2287 "{zero} compared with {value}"
2288 );
2289 }
2290 }
2291 }
2292
2293 #[test]
2294 fn fcvt_to_sint_negative_overflow_ieee128() {
2295 for (n, expected) in [
2304 (8, "-0x1.0200000000000000000000000000p7"),
2305 (16, "-0x1.0002000000000000000000000000p15"),
2306 (32, "-0x1.0000000200000000000000000000p31"),
2307 (64, "-0x1.0000000000000002000000000000p63"),
2308 ] {
2309 assert_eq!(
2310 expected,
2311 Ieee128::fcvt_to_sint_negative_overflow(n).to_string(),
2312 "n = {n}"
2313 );
2314 }
2315 }
2316}