1use super::{Round, Status, f32_from_bits, f64_from_bits};
4
5#[cfg(f16_enabled)]
7pub const fn hf16(s: &str) -> f16 {
8 match parse_hex_exact(s, 16, 10) {
9 Ok(bits) => f16::from_bits(bits as u16),
10 Err(HexFloatParseError(s)) => panic!("{}", s),
11 }
12}
13
14#[allow(unused)]
16pub const fn hf32(s: &str) -> f32 {
17 match parse_hex_exact(s, 32, 23) {
18 Ok(bits) => f32_from_bits(bits as u32),
19 Err(HexFloatParseError(s)) => panic!("{}", s),
20 }
21}
22
23pub const fn hf64(s: &str) -> f64 {
25 match parse_hex_exact(s, 64, 52) {
26 Ok(bits) => f64_from_bits(bits as u64),
27 Err(HexFloatParseError(s)) => panic!("{}", s),
28 }
29}
30
31#[cfg(f128_enabled)]
33pub const fn hf128(s: &str) -> f128 {
34 match parse_hex_exact(s, 128, 112) {
35 Ok(bits) => f128::from_bits(bits),
36 Err(HexFloatParseError(s)) => panic!("{}", s),
37 }
38}
39#[derive(Copy, Clone, Debug)]
40pub struct HexFloatParseError(&'static str);
41
42pub const fn parse_hex_exact(
44 s: &str,
45 bits: u32,
46 sig_bits: u32,
47) -> Result<u128, HexFloatParseError> {
48 match parse_any(s, bits, sig_bits, Round::Nearest) {
49 Err(e) => Err(e),
50 Ok((bits, Status::OK)) => Ok(bits),
51 Ok((_, status)) if status.overflow() => Err(HexFloatParseError("the value is too huge")),
52 Ok((_, status)) if status.underflow() => Err(HexFloatParseError("the value is too tiny")),
53 Ok((_, status)) if status.inexact() => Err(HexFloatParseError("the value is too precise")),
54 Ok(_) => unreachable!(),
55 }
56}
57
58pub const fn parse_any(
60 s: &str,
61 bits: u32,
62 sig_bits: u32,
63 round: Round,
64) -> Result<(u128, Status), HexFloatParseError> {
65 let mut b = s.as_bytes();
66
67 if sig_bits > 119 || bits > 128 || bits < sig_bits + 3 || bits > sig_bits + 30 {
68 return Err(HexFloatParseError("unsupported target float configuration"));
69 }
70
71 let neg = matches!(b, [b'-', ..]);
72 if let &[b'-' | b'+', ref rest @ ..] = b {
73 b = rest;
74 }
75
76 let sign_bit = 1 << (bits - 1);
77 let quiet_bit = 1 << (sig_bits - 1);
78 let nan = sign_bit - quiet_bit;
79 let inf = nan - quiet_bit;
80
81 let (mut x, status) = match *b {
82 [b'i' | b'I', b'n' | b'N', b'f' | b'F'] => (inf, Status::OK),
83 [b'n' | b'N', b'a' | b'A', b'n' | b'N'] => (nan, Status::OK),
84 [b'0', b'x' | b'X', ref rest @ ..] => {
85 let round = match (neg, round) {
86 (true, Round::Positive) => Round::Negative,
88 (true, Round::Negative) => Round::Positive,
89 (true, Round::Nearest | Round::Zero) | (false, _) => round,
91 };
92 match parse_finite(rest, bits, sig_bits, round) {
93 Err(e) => return Err(e),
94 Ok(res) => res,
95 }
96 }
97 _ => return Err(HexFloatParseError("no hex indicator")),
98 };
99
100 if neg {
101 x ^= sign_bit;
102 }
103
104 Ok((x, status))
105}
106
107const fn parse_finite(
108 b: &[u8],
109 bits: u32,
110 sig_bits: u32,
111 rounding_mode: Round,
112) -> Result<(u128, Status), HexFloatParseError> {
113 let exp_bits: u32 = bits - sig_bits - 1;
114 let max_msb: i32 = (1 << (exp_bits - 1)) - 1;
115 let min_lsb: i32 = 1 - max_msb - sig_bits as i32;
117
118 let (mut sig, mut exp) = match parse_hex(b) {
119 Err(e) => return Err(e),
120 Ok(Parsed { sig: 0, .. }) => return Ok((0, Status::OK)),
121 Ok(Parsed { sig, exp }) => (sig, exp),
122 };
123
124 let mut round_bits = u128_ilog2(sig) as i32 - sig_bits as i32;
125
126 if exp < min_lsb - round_bits {
128 round_bits = min_lsb - exp;
129 }
130
131 let mut status = Status::OK;
132
133 exp += round_bits;
134
135 if round_bits > 0 {
136 if round_bits == 1 {
138 sig <<= 1;
139 } else if round_bits > 2 {
140 sig = shr_odd_rounding(sig, (round_bits - 2) as u32);
141 }
142
143 if sig & 0b11 != 0 {
144 status = Status::INEXACT;
145 }
146
147 sig = shr2_round(sig, rounding_mode);
148 } else if round_bits < 0 {
149 sig <<= -round_bits;
150 }
151
152 let uexp = (exp - min_lsb) as u128;
156 let uexp = uexp << sig_bits;
157
158 debug_assert!(sig <= 2 << sig_bits);
162
163 let inf = ((1 << exp_bits) - 1) << sig_bits;
164
165 let bits = match sig.checked_add(uexp) {
166 Some(bits) if bits < inf => {
167 if status.inexact() && bits < (1 << sig_bits) {
169 status = status.with(Status::UNDERFLOW);
170 }
171 bits
172 }
173 _ => {
174 status = status.with(Status::OVERFLOW).with(Status::INEXACT);
176 match rounding_mode {
177 Round::Positive | Round::Nearest => inf,
178 Round::Negative | Round::Zero => inf - 1,
179 }
180 }
181 };
182 Ok((bits, status))
183}
184
185const fn shr_odd_rounding(x: u128, k: u32) -> u128 {
191 if k < 128 {
192 let inexact = x.trailing_zeros() < k;
193 (x >> k) | (inexact as u128)
194 } else {
195 (x != 0) as u128
196 }
197}
198
199const fn shr2_round(mut x: u128, round: Round) -> u128 {
201 let t = (x as u32) & 0b111;
202 x >>= 2;
203 match round {
204 Round::Nearest => x + ((0b11001000_u8 >> t) & 1) as u128,
206
207 Round::Negative => x,
208 Round::Zero => x,
209 Round::Positive => x + (t & 0b11 != 0) as u128,
210 }
211}
212
213struct Parsed {
215 sig: u128,
217 exp: i32,
218}
219
220const fn parse_hex(mut b: &[u8]) -> Result<Parsed, HexFloatParseError> {
222 let mut sig: u128 = 0;
223 let mut exp: i32 = 0;
224
225 let mut seen_point = false;
226 let mut some_digits = false;
227 let mut inexact = false;
228
229 while let &[c, ref rest @ ..] = b {
230 b = rest;
231
232 match c {
233 b'.' => {
234 if seen_point {
235 return Err(HexFloatParseError(
236 "unexpected '.' parsing fractional digits",
237 ));
238 }
239 seen_point = true;
240 continue;
241 }
242 b'p' | b'P' => break,
243 c => {
244 let digit = match hex_digit(c) {
245 Some(d) => d,
246 None => return Err(HexFloatParseError("expected hexadecimal digit")),
247 };
248 some_digits = true;
249
250 if (sig >> 124) == 0 {
251 sig <<= 4;
252 sig |= digit as u128;
253 } else {
254 exp += 4;
256 inexact |= digit != 0;
257 }
258 if seen_point {
262 exp -= 4;
263 }
264 }
265 }
266 }
267 sig |= inexact as u128;
272
273 if !some_digits {
274 return Err(HexFloatParseError("at least one digit is required"));
275 };
276
277 some_digits = false;
278
279 let negate_exp = matches!(b, [b'-', ..]);
280 if let &[b'-' | b'+', ref rest @ ..] = b {
281 b = rest;
282 }
283
284 let mut pexp: u32 = 0;
285 while let &[c, ref rest @ ..] = b {
286 b = rest;
287 let digit = match dec_digit(c) {
288 Some(d) => d,
289 None => return Err(HexFloatParseError("expected decimal digit")),
290 };
291 some_digits = true;
292 pexp = pexp.saturating_mul(10);
293 pexp += digit as u32;
294 }
295
296 if !some_digits {
297 return Err(HexFloatParseError(
298 "at least one exponent digit is required",
299 ));
300 };
301
302 {
303 let e;
304 if negate_exp {
305 e = (exp as i64) - (pexp as i64);
306 } else {
307 e = (exp as i64) + (pexp as i64);
308 };
309
310 exp = if e < i32::MIN as i64 {
311 i32::MIN
312 } else if e > i32::MAX as i64 {
313 i32::MAX
314 } else {
315 e as i32
316 };
317 }
318 Ok(Parsed { sig, exp })
327}
328
329const fn dec_digit(c: u8) -> Option<u8> {
330 match c {
331 b'0'..=b'9' => Some(c - b'0'),
332 _ => None,
333 }
334}
335
336const fn hex_digit(c: u8) -> Option<u8> {
337 match c {
338 b'0'..=b'9' => Some(c - b'0'),
339 b'a'..=b'f' => Some(c - b'a' + 10),
340 b'A'..=b'F' => Some(c - b'A' + 10),
341 _ => None,
342 }
343}
344
345const fn u128_ilog2(v: u128) -> u32 {
349 assert!(v != 0);
350 u128::BITS - 1 - v.leading_zeros()
351}
352
353#[cfg(any(test, feature = "unstable-public-internals"))]
354mod hex_fmt {
355 use core::fmt;
356
357 use crate::support::Float;
358
359 pub struct Hexf<F>(pub F);
361
362 #[cfg(not(feature = "compiler-builtins"))]
364 pub(super) fn fmt_any_hex<F: Float>(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::Result {
365 if x.is_sign_negative() {
366 write!(f, "-")?;
367 }
368
369 if x.is_nan() {
370 return write!(f, "NaN");
371 } else if x.is_infinite() {
372 return write!(f, "inf");
373 } else if *x == F::ZERO {
374 return write!(f, "0x0p+0");
375 }
376
377 let mut exponent = x.exp_unbiased();
378 let sig = x.to_bits() & F::SIG_MASK;
379
380 let bias = F::EXP_BIAS as i32;
381 let mshift = (4 - (F::SIG_BITS % 4)) % 4;
383 let sig = sig << mshift;
384 let mwidth = (F::SIG_BITS as usize + 3) / 4;
386 let leading = if exponent == -bias {
387 exponent += 1;
389 "0."
390 } else {
391 "1."
392 };
393
394 write!(f, "0x{leading}{sig:0mwidth$x}p{exponent:+}")
395 }
396
397 #[cfg(feature = "compiler-builtins")]
398 pub(super) fn fmt_any_hex<F: Float>(_x: &F, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
399 unimplemented!()
400 }
401
402 impl<F: Float> fmt::LowerHex for Hexf<F> {
403 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
404 cfg_if! {
405 if #[cfg(feature = "compiler-builtins")] {
406 let _ = f;
407 unimplemented!()
408 } else {
409 fmt_any_hex(&self.0, f)
410 }
411 }
412 }
413 }
414
415 impl<F: Float> fmt::LowerHex for Hexf<(F, F)> {
416 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
417 cfg_if! {
418 if #[cfg(feature = "compiler-builtins")] {
419 let _ = f;
420 unimplemented!()
421 } else {
422 write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1))
423 }
424 }
425 }
426 }
427
428 impl<F: Float> fmt::LowerHex for Hexf<(F, i32)> {
429 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
430 cfg_if! {
431 if #[cfg(feature = "compiler-builtins")] {
432 let _ = f;
433 unimplemented!()
434 } else {
435 write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1))
436 }
437 }
438 }
439 }
440
441 impl fmt::LowerHex for Hexf<i32> {
442 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
443 cfg_if! {
444 if #[cfg(feature = "compiler-builtins")] {
445 let _ = f;
446 unimplemented!()
447 } else {
448 fmt::LowerHex::fmt(&self.0, f)
449 }
450 }
451 }
452 }
453
454 impl<T> fmt::Debug for Hexf<T>
455 where
456 Hexf<T>: fmt::LowerHex,
457 {
458 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
459 cfg_if! {
460 if #[cfg(feature = "compiler-builtins")] {
461 let _ = f;
462 unimplemented!()
463 } else {
464 fmt::LowerHex::fmt(self, f)
465 }
466 }
467 }
468 }
469
470 impl<T> fmt::Display for Hexf<T>
471 where
472 Hexf<T>: fmt::LowerHex,
473 {
474 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
475 cfg_if! {
476 if #[cfg(feature = "compiler-builtins")] {
477 let _ = f;
478 unimplemented!()
479 } else {
480 fmt::LowerHex::fmt(self, f)
481 }
482 }
483 }
484 }
485}
486
487#[cfg(any(test, feature = "unstable-public-internals"))]
488pub use hex_fmt::*;
489
490#[cfg(test)]
491mod parse_tests {
492 extern crate std;
493 use std::{format, println};
494
495 use super::*;
496
497 #[cfg(f16_enabled)]
498 fn rounding_properties(s: &str) -> Result<(), HexFloatParseError> {
499 let (xd, s0) = parse_any(s, 16, 10, Round::Negative)?;
500 let (xu, s1) = parse_any(s, 16, 10, Round::Positive)?;
501 let (xz, s2) = parse_any(s, 16, 10, Round::Zero)?;
502 let (xn, s3) = parse_any(s, 16, 10, Round::Nearest)?;
503
504 if let Status::OK = s0 {
508 assert_eq!(s0, s1);
510 assert_eq!(s0, s2);
511 assert_eq!(s0, s3);
512
513 assert_eq!(xd, xu);
514 assert_eq!(xd, xz);
515 assert_eq!(xd, xn);
516 } else {
517 assert!([s0, s1, s2, s3].into_iter().all(Status::inexact));
518
519 let xd = f16::from_bits(xd as u16);
520 let xu = f16::from_bits(xu as u16);
521 let xz = f16::from_bits(xz as u16);
522 let xn = f16::from_bits(xn as u16);
523
524 assert_biteq!(xd.next_up(), xu, "s={s}, xd={xd:?}, xu={xu:?}");
525
526 let signs = [xd, xu, xz, xn].map(f16::is_sign_negative);
527
528 if signs == [true; 4] {
529 assert_biteq!(xz, xu);
530 } else {
531 assert_eq!(signs, [false; 4]);
532 assert_biteq!(xz, xd);
533 }
534
535 if xn.to_bits() != xd.to_bits() {
536 assert_biteq!(xn, xu);
537 }
538 }
539 Ok(())
540 }
541 #[test]
542 #[cfg(f16_enabled)]
543 fn test_rounding() {
544 let n = 1_i32 << 14;
545 for i in -n..n {
546 let u = i.rotate_right(11) as u32;
547 let s = format!("{}", Hexf(f32::from_bits(u)));
548 assert!(rounding_properties(&s).is_ok());
549 }
550 }
551
552 #[test]
553 fn test_parse_any() {
554 for k in -149..=127 {
555 let s = format!("0x1p{k}");
556 let x = hf32(&s);
557 let y = if k < 0 {
558 0.5f32.powi(-k)
559 } else {
560 2.0f32.powi(k)
561 };
562 assert_eq!(x, y);
563 }
564
565 let mut s = *b"0x.0000000p-121";
566 for e in 0..40 {
567 for k in 0..(1 << 15) {
568 let expected = f32::from_bits(k) * 2.0f32.powi(e);
569 let x = hf32(std::str::from_utf8(&s).unwrap());
570 assert_eq!(
571 x.to_bits(),
572 expected.to_bits(),
573 "\
574 e={e}\n\
575 k={k}\n\
576 x={x}\n\
577 expected={expected}\n\
578 s={}\n\
579 f32::from_bits(k)={}\n\
580 2.0f32.powi(e)={}\
581 ",
582 std::str::from_utf8(&s).unwrap(),
583 f32::from_bits(k),
584 2.0f32.powi(e),
585 );
586 for i in (3..10).rev() {
587 if s[i] == b'f' {
588 s[i] = b'0';
589 } else if s[i] == b'9' {
590 s[i] = b'a';
591 break;
592 } else {
593 s[i] += 1;
594 break;
595 }
596 }
597 }
598 for i in (12..15).rev() {
599 if s[i] == b'0' {
600 s[i] = b'9';
601 } else {
602 s[i] -= 1;
603 break;
604 }
605 }
606 for i in (3..10).rev() {
607 s[i] = b'0';
608 }
609 }
610 }
611
612 #[cfg(all(target_arch = "x86_64", target_os = "linux"))]
614 #[test]
615 #[cfg(f128_enabled)]
616 fn rounding() {
617 let pi = std::f128::consts::PI;
618 let s = format!("{}", Hexf(pi));
619
620 for k in 0..=111 {
621 let (bits, status) = parse_any(&s, 128 - k, 112 - k, Round::Nearest).unwrap();
622 let scale = (1u128 << (112 - k - 1)) as f128;
623 let expected = (pi * scale).round_ties_even() / scale;
624 assert_eq!(bits << k, expected.to_bits(), "k = {k}, s = {s}");
625 assert_eq!(expected != pi, status.inexact());
626 }
627 }
628 #[test]
629 fn rounding_extreme_underflow() {
630 for k in 1..1000 {
631 let s = format!("0x1p{}", -149 - k);
632 let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else {
633 unreachable!()
634 };
635 assert_eq!(bits, 0, "{s} should round to zero, got bits={bits}");
636 assert!(
637 status.underflow(),
638 "should indicate underflow when parsing {s}"
639 );
640 assert!(status.inexact(), "should indicate inexact when parsing {s}");
641 }
642 }
643 #[test]
644 fn long_tail() {
645 for k in 1..1000 {
646 let s = format!("0x1.{}p0", "0".repeat(k));
647 let Ok(bits) = parse_hex_exact(&s, 32, 23) else {
648 panic!("parsing {s} failed")
649 };
650 assert_eq!(f32::from_bits(bits as u32), 1.0);
651
652 let s = format!("0x1.{}1p0", "0".repeat(k));
653 let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else {
654 unreachable!()
655 };
656 if status.inexact() {
657 assert!(1.0 == f32::from_bits(bits as u32));
658 } else {
659 assert!(1.0 < f32::from_bits(bits as u32));
660 }
661 }
662 }
663 #[cfg(f16_enabled)]
666 macro_rules! f16_tests {
667 () => {
668 #[test]
669 fn test_f16() {
670 let checks = [
671 ("0x.1234p+16", (0x1234 as f16).to_bits()),
672 ("0x1.234p+12", (0x1234 as f16).to_bits()),
673 ("0x12.34p+8", (0x1234 as f16).to_bits()),
674 ("0x123.4p+4", (0x1234 as f16).to_bits()),
675 ("0x1234p+0", (0x1234 as f16).to_bits()),
676 ("0x1234.p+0", (0x1234 as f16).to_bits()),
677 ("0x1234.0p+0", (0x1234 as f16).to_bits()),
678 ("0x1.ffcp+15", f16::MAX.to_bits()),
679 ("0x1.0p+1", 2.0f16.to_bits()),
680 ("0x1.0p+0", 1.0f16.to_bits()),
681 ("0x1.ffp+8", 0x5ffc),
682 ("+0x1.ffp+8", 0x5ffc),
683 ("0x1p+0", 0x3c00),
684 ("0x1.998p-4", 0x2e66),
685 ("0x1.9p+6", 0x5640),
686 ("0x0.0p0", 0.0f16.to_bits()),
687 ("-0x0.0p0", (-0.0f16).to_bits()),
688 ("0x1.0p0", 1.0f16.to_bits()),
689 ("0x1.998p-4", (0.1f16).to_bits()),
690 ("-0x1.998p-4", (-0.1f16).to_bits()),
691 ("0x0.123p-12", 0x0123),
692 ("0x1p-24", 0x0001),
693 ("nan", f16::NAN.to_bits()),
694 ("-nan", (-f16::NAN).to_bits()),
695 ("inf", f16::INFINITY.to_bits()),
696 ("-inf", f16::NEG_INFINITY.to_bits()),
697 ];
698 for (s, exp) in checks {
699 println!("parsing {s}");
700 assert!(rounding_properties(s).is_ok());
701 let act = hf16(s).to_bits();
702 assert_eq!(
703 act, exp,
704 "parsing {s}: {act:#06x} != {exp:#06x}\nact: {act:#018b}\nexp: {exp:#018b}"
705 );
706 }
707 }
708
709 #[test]
710 fn test_macros_f16() {
711 assert_eq!(hf16!("0x1.ffp+8").to_bits(), 0x5ffc_u16);
712 }
713 };
714 }
715
716 #[cfg(f16_enabled)]
717 f16_tests!();
718
719 #[test]
720 fn test_f32() {
721 let checks = [
722 ("0x.1234p+16", (0x1234 as f32).to_bits()),
723 ("0x1.234p+12", (0x1234 as f32).to_bits()),
724 ("0x12.34p+8", (0x1234 as f32).to_bits()),
725 ("0x123.4p+4", (0x1234 as f32).to_bits()),
726 ("0x1234p+0", (0x1234 as f32).to_bits()),
727 ("0x1234.p+0", (0x1234 as f32).to_bits()),
728 ("0x1234.0p+0", (0x1234 as f32).to_bits()),
729 ("0x1.fffffep+127", f32::MAX.to_bits()),
730 ("0x1.0p+1", 2.0f32.to_bits()),
731 ("0x1.0p+0", 1.0f32.to_bits()),
732 ("0x1.ffep+8", 0x43fff000),
733 ("+0x1.ffep+8", 0x43fff000),
734 ("0x1p+0", 0x3f800000),
735 ("0x1.99999ap-4", 0x3dcccccd),
736 ("0x1.9p+6", 0x42c80000),
737 ("0x1.2d5ed2p+20", 0x4996af69),
738 ("-0x1.348eb8p+10", 0xc49a475c),
739 ("-0x1.33dcfep-33", 0xaf19ee7f),
740 ("0x0.0p0", 0.0f32.to_bits()),
741 ("-0x0.0p0", (-0.0f32).to_bits()),
742 ("0x1.0p0", 1.0f32.to_bits()),
743 ("0x1.99999ap-4", (0.1f32).to_bits()),
744 ("-0x1.99999ap-4", (-0.1f32).to_bits()),
745 ("0x1.111114p-127", 0x00444445),
746 ("0x1.23456p-130", 0x00091a2b),
747 ("0x1p-149", 0x00000001),
748 ("nan", f32::NAN.to_bits()),
749 ("-nan", (-f32::NAN).to_bits()),
750 ("inf", f32::INFINITY.to_bits()),
751 ("-inf", f32::NEG_INFINITY.to_bits()),
752 ];
753 for (s, exp) in checks {
754 println!("parsing {s}");
755 let act = hf32(s).to_bits();
756 assert_eq!(
757 act, exp,
758 "parsing {s}: {act:#010x} != {exp:#010x}\nact: {act:#034b}\nexp: {exp:#034b}"
759 );
760 }
761 }
762
763 #[test]
764 fn test_f64() {
765 let checks = [
766 ("0x.1234p+16", (0x1234 as f64).to_bits()),
767 ("0x1.234p+12", (0x1234 as f64).to_bits()),
768 ("0x12.34p+8", (0x1234 as f64).to_bits()),
769 ("0x123.4p+4", (0x1234 as f64).to_bits()),
770 ("0x1234p+0", (0x1234 as f64).to_bits()),
771 ("0x1234.p+0", (0x1234 as f64).to_bits()),
772 ("0x1234.0p+0", (0x1234 as f64).to_bits()),
773 ("0x1.ffep+8", 0x407ffe0000000000),
774 ("0x1p+0", 0x3ff0000000000000),
775 ("0x1.999999999999ap-4", 0x3fb999999999999a),
776 ("0x1.9p+6", 0x4059000000000000),
777 ("0x1.2d5ed1fe1da7bp+20", 0x4132d5ed1fe1da7b),
778 ("-0x1.348eb851eb852p+10", 0xc09348eb851eb852),
779 ("-0x1.33dcfe54a3803p-33", 0xbde33dcfe54a3803),
780 ("0x1.0p0", 1.0f64.to_bits()),
781 ("0x0.0p0", 0.0f64.to_bits()),
782 ("-0x0.0p0", (-0.0f64).to_bits()),
783 ("0x1.999999999999ap-4", 0.1f64.to_bits()),
784 ("0x1.999999999998ap-4", (0.1f64 - f64::EPSILON).to_bits()),
785 ("-0x1.999999999999ap-4", (-0.1f64).to_bits()),
786 ("-0x1.999999999998ap-4", (-0.1f64 + f64::EPSILON).to_bits()),
787 ("0x0.8000000000001p-1022", 0x0008000000000001),
788 ("0x0.123456789abcdp-1022", 0x000123456789abcd),
789 ("0x0.0000000000002p-1022", 0x0000000000000002),
790 ("nan", f64::NAN.to_bits()),
791 ("-nan", (-f64::NAN).to_bits()),
792 ("inf", f64::INFINITY.to_bits()),
793 ("-inf", f64::NEG_INFINITY.to_bits()),
794 ];
795 for (s, exp) in checks {
796 println!("parsing {s}");
797 let act = hf64(s).to_bits();
798 assert_eq!(
799 act, exp,
800 "parsing {s}: {act:#018x} != {exp:#018x}\nact: {act:#066b}\nexp: {exp:#066b}"
801 );
802 }
803 }
804
805 #[cfg(f128_enabled)]
808 macro_rules! f128_tests {
809 () => {
810 #[test]
811 fn test_f128() {
812 let checks = [
813 ("0x.1234p+16", (0x1234 as f128).to_bits()),
814 ("0x1.234p+12", (0x1234 as f128).to_bits()),
815 ("0x12.34p+8", (0x1234 as f128).to_bits()),
816 ("0x123.4p+4", (0x1234 as f128).to_bits()),
817 ("0x1234p+0", (0x1234 as f128).to_bits()),
818 ("0x1234.p+0", (0x1234 as f128).to_bits()),
819 ("0x1234.0p+0", (0x1234 as f128).to_bits()),
820 ("0x1.ffffffffffffffffffffffffffffp+16383", f128::MAX.to_bits()),
821 ("0x1.0p+1", 2.0f128.to_bits()),
822 ("0x1.0p+0", 1.0f128.to_bits()),
823 ("0x1.ffep+8", 0x4007ffe0000000000000000000000000),
824 ("+0x1.ffep+8", 0x4007ffe0000000000000000000000000),
825 ("0x1p+0", 0x3fff0000000000000000000000000000),
826 ("0x1.999999999999999999999999999ap-4", 0x3ffb999999999999999999999999999a),
827 ("0x1.9p+6", 0x40059000000000000000000000000000),
828 ("0x0.0p0", 0.0f128.to_bits()),
829 ("-0x0.0p0", (-0.0f128).to_bits()),
830 ("0x1.0p0", 1.0f128.to_bits()),
831 ("0x1.999999999999999999999999999ap-4", (0.1f128).to_bits()),
832 ("-0x1.999999999999999999999999999ap-4", (-0.1f128).to_bits()),
833 ("0x0.abcdef0123456789abcdef012345p-16382", 0x0000abcdef0123456789abcdef012345),
834 ("0x1p-16494", 0x00000000000000000000000000000001),
835 ("nan", f128::NAN.to_bits()),
836 ("-nan", (-f128::NAN).to_bits()),
837 ("inf", f128::INFINITY.to_bits()),
838 ("-inf", f128::NEG_INFINITY.to_bits()),
839 ];
840 for (s, exp) in checks {
841 println!("parsing {s}");
842 let act = hf128(s).to_bits();
843 assert_eq!(
844 act, exp,
845 "parsing {s}: {act:#034x} != {exp:#034x}\nact: {act:#0130b}\nexp: {exp:#0130b}"
846 );
847 }
848 }
849
850 #[test]
851 fn test_macros_f128() {
852 assert_eq!(hf128!("0x1.ffep+8").to_bits(), 0x4007ffe0000000000000000000000000_u128);
853 }
854 }
855 }
856
857 #[cfg(f128_enabled)]
858 f128_tests!();
859
860 #[test]
861 fn test_macros() {
862 #[cfg(f16_enabled)]
863 assert_eq!(hf16!("0x1.ffp+8").to_bits(), 0x5ffc_u16);
864 assert_eq!(hf32!("0x1.ffep+8").to_bits(), 0x43fff000_u32);
865 assert_eq!(hf64!("0x1.ffep+8").to_bits(), 0x407ffe0000000000_u64);
866 #[cfg(f128_enabled)]
867 assert_eq!(
868 hf128!("0x1.ffep+8").to_bits(),
869 0x4007ffe0000000000000000000000000_u128
870 );
871 }
872}
873
874#[cfg(test)]
875#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))]
877mod tests_panicking {
878 extern crate std;
879 use super::*;
880
881 #[cfg(f16_enabled)]
884 macro_rules! f16_tests {
885 () => {
886 #[test]
887 fn test_f16_almost_extra_precision() {
888 hf16("0x1.ffcp+0");
890 }
891
892 #[test]
893 #[should_panic(expected = "the value is too precise")]
894 fn test_f16_extra_precision() {
895 hf16("0x1.ffdp+0");
897 }
898
899 #[test]
900 #[should_panic(expected = "the value is too huge")]
901 fn test_f16_overflow() {
902 hf16("0x1p+16");
904 }
905
906 #[test]
907 fn test_f16_tiniest() {
908 let x = hf16("0x1.p-24");
909 let y = hf16("0x0.001p-12");
910 let z = hf16("0x0.8p-23");
911 assert_eq!(x, y);
912 assert_eq!(x, z);
913 }
914
915 #[test]
916 #[should_panic(expected = "the value is too tiny")]
917 fn test_f16_too_tiny() {
918 hf16("0x1.p-25");
919 }
920
921 #[test]
922 #[should_panic(expected = "the value is too tiny")]
923 fn test_f16_also_too_tiny() {
924 hf16("0x0.8p-24");
925 }
926
927 #[test]
928 #[should_panic(expected = "the value is too tiny")]
929 fn test_f16_again_too_tiny() {
930 hf16("0x0.001p-13");
931 }
932 };
933 }
934
935 #[cfg(f16_enabled)]
936 f16_tests!();
937
938 #[test]
939 fn test_f32_almost_extra_precision() {
940 hf32("0x1.abcdeep+0");
942 }
943
944 #[test]
945 #[should_panic]
946 fn test_f32_extra_precision2() {
947 hf32("0x1.ffffffp+127");
949 }
950
951 #[test]
952 #[should_panic(expected = "the value is too huge")]
953 fn test_f32_overflow() {
954 hf32("0x1p+128");
956 }
957
958 #[test]
959 #[should_panic(expected = "the value is too precise")]
960 fn test_f32_extra_precision() {
961 hf32("0x1.abcdefp+0");
963 }
964
965 #[test]
966 fn test_f32_tiniest() {
967 let x = hf32("0x1.p-149");
968 let y = hf32("0x0.0000000000000001p-85");
969 let z = hf32("0x0.8p-148");
970 assert_eq!(x, y);
971 assert_eq!(x, z);
972 }
973
974 #[test]
975 #[should_panic(expected = "the value is too tiny")]
976 fn test_f32_too_tiny() {
977 hf32("0x1.p-150");
978 }
979
980 #[test]
981 #[should_panic(expected = "the value is too tiny")]
982 fn test_f32_also_too_tiny() {
983 hf32("0x0.8p-149");
984 }
985
986 #[test]
987 #[should_panic(expected = "the value is too tiny")]
988 fn test_f32_again_too_tiny() {
989 hf32("0x0.0000000000000001p-86");
990 }
991
992 #[test]
993 fn test_f64_almost_extra_precision() {
994 hf64("0x1.abcdabcdabcdfp+0");
996 }
997
998 #[test]
999 #[should_panic(expected = "the value is too precise")]
1000 fn test_f64_extra_precision() {
1001 hf64("0x1.abcdabcdabcdf8p+0");
1003 }
1004
1005 #[cfg(f128_enabled)]
1008 macro_rules! f128_tests {
1009 () => {
1010 #[test]
1011 fn test_f128_almost_extra_precision() {
1012 hf128("0x1.ffffffffffffffffffffffffffffp+16383");
1014 }
1015
1016 #[test]
1017 #[should_panic(expected = "the value is too precise")]
1018 fn test_f128_extra_precision() {
1019 hf128("0x1.fffffffffffffffffffffffffffe8p+16383");
1021 }
1022 #[test]
1023 #[should_panic(expected = "the value is too huge")]
1024 fn test_f128_extra_precision_overflow() {
1025 hf128("0x1.ffffffffffffffffffffffffffff8p+16383");
1027 }
1028
1029 #[test]
1030 #[should_panic(expected = "the value is too huge")]
1031 fn test_f128_overflow() {
1032 hf128("0x1p+16384");
1034 }
1035
1036 #[test]
1037 fn test_f128_tiniest() {
1038 let x = hf128("0x1.p-16494");
1039 let y = hf128("0x0.0000000000000001p-16430");
1040 let z = hf128("0x0.8p-16493");
1041 assert_eq!(x, y);
1042 assert_eq!(x, z);
1043 }
1044
1045 #[test]
1046 #[should_panic(expected = "the value is too tiny")]
1047 fn test_f128_too_tiny() {
1048 hf128("0x1.p-16495");
1049 }
1050
1051 #[test]
1052 #[should_panic(expected = "the value is too tiny")]
1053 fn test_f128_again_too_tiny() {
1054 hf128("0x0.0000000000000001p-16431");
1055 }
1056
1057 #[test]
1058 #[should_panic(expected = "the value is too tiny")]
1059 fn test_f128_also_too_tiny() {
1060 hf128("0x0.8p-16494");
1061 }
1062 };
1063 }
1064
1065 #[cfg(f128_enabled)]
1066 f128_tests!();
1067}
1068
1069#[cfg(test)]
1070mod print_tests {
1071 extern crate std;
1072 use std::string::ToString;
1073
1074 use super::*;
1075 use crate::support::Float;
1076
1077 #[test]
1078 #[cfg(f16_enabled)]
1079 fn test_f16() {
1080 use std::format;
1081 for x in 0..=u16::MAX {
1083 let f = f16::from_bits(x);
1084 let s = format!("{}", Hexf(f));
1085 let from_s = hf16(&s);
1086
1087 if f.is_nan() && from_s.is_nan() {
1088 continue;
1089 }
1090
1091 assert_eq!(
1092 f.to_bits(),
1093 from_s.to_bits(),
1094 "{f:?} formatted as {s} but parsed as {from_s:?}"
1095 );
1096 }
1097 }
1098
1099 #[test]
1100 #[cfg(f16_enabled)]
1101 fn test_f16_to_f32() {
1102 use std::format;
1103 for x in 0..=u16::MAX {
1109 let f16 = f16::from_bits(x);
1110 let s16 = format!("{}", Hexf(f16));
1111 let f32 = f16 as f32;
1112 let s32 = format!("{}", Hexf(f32));
1113
1114 let a = hf32(&s16);
1115 let b = hf32(&s32);
1116 let c = hf16(&s32);
1117
1118 if f32.is_nan() && a.is_nan() && b.is_nan() && c.is_nan() {
1119 continue;
1120 }
1121
1122 assert_eq!(
1123 f32.to_bits(),
1124 a.to_bits(),
1125 "{f16:?} : f16 formatted as {s16} which parsed as {a:?} : f16"
1126 );
1127 assert_eq!(
1128 f32.to_bits(),
1129 b.to_bits(),
1130 "{f32:?} : f32 formatted as {s32} which parsed as {b:?} : f32"
1131 );
1132 assert_eq!(
1133 f32.to_bits(),
1134 (c as f32).to_bits(),
1135 "{f32:?} : f32 formatted as {s32} which parsed as {c:?} : f16"
1136 );
1137 }
1138 }
1139 #[test]
1140 fn spot_checks() {
1141 assert_eq!(Hexf(f32::MAX).to_string(), "0x1.fffffep+127");
1142 assert_eq!(Hexf(f64::MAX).to_string(), "0x1.fffffffffffffp+1023");
1143
1144 assert_eq!(Hexf(f32::MIN).to_string(), "-0x1.fffffep+127");
1145 assert_eq!(Hexf(f64::MIN).to_string(), "-0x1.fffffffffffffp+1023");
1146
1147 assert_eq!(Hexf(f32::ZERO).to_string(), "0x0p+0");
1148 assert_eq!(Hexf(f64::ZERO).to_string(), "0x0p+0");
1149
1150 assert_eq!(Hexf(f32::NEG_ZERO).to_string(), "-0x0p+0");
1151 assert_eq!(Hexf(f64::NEG_ZERO).to_string(), "-0x0p+0");
1152
1153 assert_eq!(Hexf(f32::NAN).to_string(), "NaN");
1154 assert_eq!(Hexf(f64::NAN).to_string(), "NaN");
1155
1156 assert_eq!(Hexf(f32::INFINITY).to_string(), "inf");
1157 assert_eq!(Hexf(f64::INFINITY).to_string(), "inf");
1158
1159 assert_eq!(Hexf(f32::NEG_INFINITY).to_string(), "-inf");
1160 assert_eq!(Hexf(f64::NEG_INFINITY).to_string(), "-inf");
1161
1162 #[cfg(f16_enabled)]
1163 {
1164 assert_eq!(Hexf(f16::MAX).to_string(), "0x1.ffcp+15");
1165 assert_eq!(Hexf(f16::MIN).to_string(), "-0x1.ffcp+15");
1166 assert_eq!(Hexf(f16::ZERO).to_string(), "0x0p+0");
1167 assert_eq!(Hexf(f16::NEG_ZERO).to_string(), "-0x0p+0");
1168 assert_eq!(Hexf(f16::NAN).to_string(), "NaN");
1169 assert_eq!(Hexf(f16::INFINITY).to_string(), "inf");
1170 assert_eq!(Hexf(f16::NEG_INFINITY).to_string(), "-inf");
1171 }
1172
1173 #[cfg(f128_enabled)]
1174 {
1175 assert_eq!(
1176 Hexf(f128::MAX).to_string(),
1177 "0x1.ffffffffffffffffffffffffffffp+16383"
1178 );
1179 assert_eq!(
1180 Hexf(f128::MIN).to_string(),
1181 "-0x1.ffffffffffffffffffffffffffffp+16383"
1182 );
1183 assert_eq!(Hexf(f128::ZERO).to_string(), "0x0p+0");
1184 assert_eq!(Hexf(f128::NEG_ZERO).to_string(), "-0x0p+0");
1185 assert_eq!(Hexf(f128::NAN).to_string(), "NaN");
1186 assert_eq!(Hexf(f128::INFINITY).to_string(), "inf");
1187 assert_eq!(Hexf(f128::NEG_INFINITY).to_string(), "-inf");
1188 }
1189 }
1190}