|
1 | 1 | //! Utilities for working with hex float formats. |
2 | 2 |
|
3 | | -use core::fmt; |
4 | | - |
5 | | -use super::{Float, Round, Status, f32_from_bits, f64_from_bits}; |
| 3 | +use super::{Round, Status, f32_from_bits, f64_from_bits}; |
6 | 4 |
|
7 | 5 | /// Construct a 16-bit float from hex float representation (C-style) |
8 | 6 | #[cfg(f16_enabled)] |
@@ -352,133 +350,143 @@ const fn u128_ilog2(v: u128) -> u32 { |
352 | 350 | u128::BITS - 1 - v.leading_zeros() |
353 | 351 | } |
354 | 352 |
|
355 | | -/// Format a floating point number as its IEEE hex (`%a`) representation. |
356 | | -pub struct Hexf<F>(pub F); |
| 353 | +#[cfg(any(test, feature = "unstable-public-internals"))] |
| 354 | +mod hex_fmt { |
| 355 | + use core::fmt; |
357 | 356 |
|
358 | | -// Adapted from https://github.com/ericseppanen/hexfloat2/blob/a5c27932f0ff/src/format.rs |
359 | | -#[cfg(not(feature = "compiler-builtins"))] |
360 | | -fn fmt_any_hex<F: Float>(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
361 | | - if x.is_sign_negative() { |
362 | | - write!(f, "-")?; |
363 | | - } |
| 357 | + use crate::support::Float; |
364 | 358 |
|
365 | | - if x.is_nan() { |
366 | | - return write!(f, "NaN"); |
367 | | - } else if x.is_infinite() { |
368 | | - return write!(f, "inf"); |
369 | | - } else if *x == F::ZERO { |
370 | | - return write!(f, "0x0p+0"); |
371 | | - } |
| 359 | + /// Format a floating point number as its IEEE hex (`%a`) representation. |
| 360 | + pub struct Hexf<F>(pub F); |
372 | 361 |
|
373 | | - let mut exponent = x.exp_unbiased(); |
374 | | - let sig = x.to_bits() & F::SIG_MASK; |
375 | | - |
376 | | - let bias = F::EXP_BIAS as i32; |
377 | | - // The mantissa MSB needs to be shifted up to the nearest nibble. |
378 | | - let mshift = (4 - (F::SIG_BITS % 4)) % 4; |
379 | | - let sig = sig << mshift; |
380 | | - // The width is rounded up to the nearest char (4 bits) |
381 | | - let mwidth = (F::SIG_BITS as usize + 3) / 4; |
382 | | - let leading = if exponent == -bias { |
383 | | - // subnormal number means we shift our output by 1 bit. |
384 | | - exponent += 1; |
385 | | - "0." |
386 | | - } else { |
387 | | - "1." |
388 | | - }; |
| 362 | + // Adapted from https://github.com/ericseppanen/hexfloat2/blob/a5c27932f0ff/src/format.rs |
| 363 | + #[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 | + } |
389 | 368 |
|
390 | | - write!(f, "0x{leading}{sig:0mwidth$x}p{exponent:+}") |
391 | | -} |
| 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 | + } |
392 | 376 |
|
393 | | -#[cfg(feature = "compiler-builtins")] |
394 | | -fn fmt_any_hex<F: Float>(_x: &F, _f: &mut fmt::Formatter<'_>) -> fmt::Result { |
395 | | - unimplemented!() |
396 | | -} |
| 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 | + // The mantissa MSB needs to be shifted up to the nearest nibble. |
| 382 | + let mshift = (4 - (F::SIG_BITS % 4)) % 4; |
| 383 | + let sig = sig << mshift; |
| 384 | + // The width is rounded up to the nearest char (4 bits) |
| 385 | + let mwidth = (F::SIG_BITS as usize + 3) / 4; |
| 386 | + let leading = if exponent == -bias { |
| 387 | + // subnormal number means we shift our output by 1 bit. |
| 388 | + exponent += 1; |
| 389 | + "0." |
| 390 | + } else { |
| 391 | + "1." |
| 392 | + }; |
397 | 393 |
|
398 | | -impl<F: Float> fmt::LowerHex for Hexf<F> { |
399 | | - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
400 | | - cfg_if! { |
401 | | - if #[cfg(feature = "compiler-builtins")] { |
402 | | - let _ = f; |
403 | | - unimplemented!() |
404 | | - } else { |
405 | | - fmt_any_hex(&self.0, f) |
| 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 | + } |
406 | 411 | } |
407 | 412 | } |
408 | 413 | } |
409 | | -} |
410 | 414 |
|
411 | | -impl<F: Float> fmt::LowerHex for Hexf<(F, F)> { |
412 | | - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
413 | | - cfg_if! { |
414 | | - if #[cfg(feature = "compiler-builtins")] { |
415 | | - let _ = f; |
416 | | - unimplemented!() |
417 | | - } else { |
418 | | - write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) |
| 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 | + } |
419 | 424 | } |
420 | 425 | } |
421 | 426 | } |
422 | | -} |
423 | 427 |
|
424 | | -impl<F: Float> fmt::LowerHex for Hexf<(F, i32)> { |
425 | | - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
426 | | - cfg_if! { |
427 | | - if #[cfg(feature = "compiler-builtins")] { |
428 | | - let _ = f; |
429 | | - unimplemented!() |
430 | | - } else { |
431 | | - write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) |
| 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 | + } |
432 | 437 | } |
433 | 438 | } |
434 | 439 | } |
435 | | -} |
436 | 440 |
|
437 | | -impl fmt::LowerHex for Hexf<i32> { |
438 | | - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
439 | | - cfg_if! { |
440 | | - if #[cfg(feature = "compiler-builtins")] { |
441 | | - let _ = f; |
442 | | - unimplemented!() |
443 | | - } else { |
444 | | - fmt::LowerHex::fmt(&self.0, f) |
| 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 | + } |
445 | 450 | } |
446 | 451 | } |
447 | 452 | } |
448 | | -} |
449 | 453 |
|
450 | | -impl<T> fmt::Debug for Hexf<T> |
451 | | -where |
452 | | - Hexf<T>: fmt::LowerHex, |
453 | | -{ |
454 | | - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
455 | | - cfg_if! { |
456 | | - if #[cfg(feature = "compiler-builtins")] { |
457 | | - let _ = f; |
458 | | - unimplemented!() |
459 | | - } else { |
460 | | - fmt::LowerHex::fmt(self, f) |
| 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 | + } |
461 | 466 | } |
462 | 467 | } |
463 | 468 | } |
464 | | -} |
465 | 469 |
|
466 | | -impl<T> fmt::Display for Hexf<T> |
467 | | -where |
468 | | - Hexf<T>: fmt::LowerHex, |
469 | | -{ |
470 | | - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
471 | | - cfg_if! { |
472 | | - if #[cfg(feature = "compiler-builtins")] { |
473 | | - let _ = f; |
474 | | - unimplemented!() |
475 | | - } else { |
476 | | - fmt::LowerHex::fmt(self, f) |
| 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 | + } |
477 | 482 | } |
478 | 483 | } |
479 | 484 | } |
480 | 485 | } |
481 | 486 |
|
| 487 | +#[cfg(any(test, feature = "unstable-public-internals"))] |
| 488 | +pub use hex_fmt::*; |
| 489 | + |
482 | 490 | #[cfg(test)] |
483 | 491 | mod parse_tests { |
484 | 492 | extern crate std; |
@@ -1064,6 +1072,7 @@ mod print_tests { |
1064 | 1072 | use std::string::ToString; |
1065 | 1073 |
|
1066 | 1074 | use super::*; |
| 1075 | + use crate::support::Float; |
1067 | 1076 |
|
1068 | 1077 | #[test] |
1069 | 1078 | #[cfg(f16_enabled)] |
|
0 commit comments