Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libm/src/math/support/float_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use super::int_traits::{CastFrom, Int, MinInt};

/// Trait for some basic operations on floats
// #[allow(dead_code)]
#[allow(dead_code)] // Some constants are only used with tests
pub trait Float:
Copy
+ fmt::Debug
Expand Down
207 changes: 108 additions & 99 deletions libm/src/math/support/hex_float.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
//! Utilities for working with hex float formats.

use core::fmt;

use super::{Float, Round, Status, f32_from_bits, f64_from_bits};
use super::{Round, Status, f32_from_bits, f64_from_bits};

/// Construct a 16-bit float from hex float representation (C-style)
#[cfg(f16_enabled)]
Expand Down Expand Up @@ -352,133 +350,143 @@ const fn u128_ilog2(v: u128) -> u32 {
u128::BITS - 1 - v.leading_zeros()
}

/// Format a floating point number as its IEEE hex (`%a`) representation.
pub struct Hexf<F>(pub F);
#[cfg(any(test, feature = "unstable-public-internals"))]
mod hex_fmt {
use core::fmt;

// Adapted from https://github.com/ericseppanen/hexfloat2/blob/a5c27932f0ff/src/format.rs
#[cfg(not(feature = "compiler-builtins"))]
fn fmt_any_hex<F: Float>(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if x.is_sign_negative() {
write!(f, "-")?;
}
use crate::support::Float;

if x.is_nan() {
return write!(f, "NaN");
} else if x.is_infinite() {
return write!(f, "inf");
} else if *x == F::ZERO {
return write!(f, "0x0p+0");
}
/// Format a floating point number as its IEEE hex (`%a`) representation.
pub struct Hexf<F>(pub F);

let mut exponent = x.exp_unbiased();
let sig = x.to_bits() & F::SIG_MASK;

let bias = F::EXP_BIAS as i32;
// The mantissa MSB needs to be shifted up to the nearest nibble.
let mshift = (4 - (F::SIG_BITS % 4)) % 4;
let sig = sig << mshift;
// The width is rounded up to the nearest char (4 bits)
let mwidth = (F::SIG_BITS as usize + 3) / 4;
let leading = if exponent == -bias {
// subnormal number means we shift our output by 1 bit.
exponent += 1;
"0."
} else {
"1."
};
// Adapted from https://github.com/ericseppanen/hexfloat2/blob/a5c27932f0ff/src/format.rs
#[cfg(not(feature = "compiler-builtins"))]
pub(super) fn fmt_any_hex<F: Float>(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if x.is_sign_negative() {
write!(f, "-")?;
}

write!(f, "0x{leading}{sig:0mwidth$x}p{exponent:+}")
}
if x.is_nan() {
return write!(f, "NaN");
} else if x.is_infinite() {
return write!(f, "inf");
} else if *x == F::ZERO {
return write!(f, "0x0p+0");
}

#[cfg(feature = "compiler-builtins")]
fn fmt_any_hex<F: Float>(_x: &F, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
unimplemented!()
}
let mut exponent = x.exp_unbiased();
let sig = x.to_bits() & F::SIG_MASK;

let bias = F::EXP_BIAS as i32;
// The mantissa MSB needs to be shifted up to the nearest nibble.
let mshift = (4 - (F::SIG_BITS % 4)) % 4;
let sig = sig << mshift;
// The width is rounded up to the nearest char (4 bits)
let mwidth = (F::SIG_BITS as usize + 3) / 4;
let leading = if exponent == -bias {
// subnormal number means we shift our output by 1 bit.
exponent += 1;
"0."
} else {
"1."
};

impl<F: Float> fmt::LowerHex for Hexf<F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cfg_if! {
if #[cfg(feature = "compiler-builtins")] {
let _ = f;
unimplemented!()
} else {
fmt_any_hex(&self.0, f)
write!(f, "0x{leading}{sig:0mwidth$x}p{exponent:+}")
}

#[cfg(feature = "compiler-builtins")]
pub(super) fn fmt_any_hex<F: Float>(_x: &F, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
unimplemented!()
}

impl<F: Float> fmt::LowerHex for Hexf<F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cfg_if! {
if #[cfg(feature = "compiler-builtins")] {
let _ = f;
unimplemented!()
} else {
fmt_any_hex(&self.0, f)
}
}
}
}
}

impl<F: Float> fmt::LowerHex for Hexf<(F, F)> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cfg_if! {
if #[cfg(feature = "compiler-builtins")] {
let _ = f;
unimplemented!()
} else {
write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1))
impl<F: Float> fmt::LowerHex for Hexf<(F, F)> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cfg_if! {
if #[cfg(feature = "compiler-builtins")] {
let _ = f;
unimplemented!()
} else {
write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1))
}
}
}
}
}

impl<F: Float> fmt::LowerHex for Hexf<(F, i32)> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cfg_if! {
if #[cfg(feature = "compiler-builtins")] {
let _ = f;
unimplemented!()
} else {
write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1))
impl<F: Float> fmt::LowerHex for Hexf<(F, i32)> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cfg_if! {
if #[cfg(feature = "compiler-builtins")] {
let _ = f;
unimplemented!()
} else {
write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1))
}
}
}
}
}

impl fmt::LowerHex for Hexf<i32> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cfg_if! {
if #[cfg(feature = "compiler-builtins")] {
let _ = f;
unimplemented!()
} else {
fmt::LowerHex::fmt(&self.0, f)
impl fmt::LowerHex for Hexf<i32> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cfg_if! {
if #[cfg(feature = "compiler-builtins")] {
let _ = f;
unimplemented!()
} else {
fmt::LowerHex::fmt(&self.0, f)
}
}
}
}
}

impl<T> fmt::Debug for Hexf<T>
where
Hexf<T>: fmt::LowerHex,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cfg_if! {
if #[cfg(feature = "compiler-builtins")] {
let _ = f;
unimplemented!()
} else {
fmt::LowerHex::fmt(self, f)
impl<T> fmt::Debug for Hexf<T>
where
Hexf<T>: fmt::LowerHex,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cfg_if! {
if #[cfg(feature = "compiler-builtins")] {
let _ = f;
unimplemented!()
} else {
fmt::LowerHex::fmt(self, f)
}
}
}
}
}

impl<T> fmt::Display for Hexf<T>
where
Hexf<T>: fmt::LowerHex,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cfg_if! {
if #[cfg(feature = "compiler-builtins")] {
let _ = f;
unimplemented!()
} else {
fmt::LowerHex::fmt(self, f)
impl<T> fmt::Display for Hexf<T>
where
Hexf<T>: fmt::LowerHex,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cfg_if! {
if #[cfg(feature = "compiler-builtins")] {
let _ = f;
unimplemented!()
} else {
fmt::LowerHex::fmt(self, f)
}
}
}
}
}

#[cfg(any(test, feature = "unstable-public-internals"))]
pub use hex_fmt::*;

#[cfg(test)]
mod parse_tests {
extern crate std;
Expand Down Expand Up @@ -1064,6 +1072,7 @@ mod print_tests {
use std::string::ToString;

use super::*;
use crate::support::Float;

#[test]
#[cfg(f16_enabled)]
Expand Down
1 change: 1 addition & 0 deletions libm/src/math/support/int_traits.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use core::{cmp, fmt, ops};

/// Minimal integer implementations needed on all integer types, including wide integers.
#[allow(dead_code)] // Some constants are only used with tests
pub trait MinInt:
Copy
+ fmt::Debug
Expand Down
6 changes: 3 additions & 3 deletions libm/src/math/support/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,12 @@ macro_rules! hf128 {
#[cfg(test)]
macro_rules! assert_biteq {
($left:expr, $right:expr, $($tt:tt)*) => {{
use $crate::support::Int;
let l = $left;
let r = $right;
let bits = Int::leading_zeros(l.to_bits() - l.to_bits()); // hack to get the width from the value
// hack to get width from a value
let bits = $crate::support::Int::leading_zeros(l.to_bits() - l.to_bits());
assert!(
l.biteq(r),
$crate::support::Float::biteq(l, r),
"{}\nl: {l:?} ({lb:#0width$x})\nr: {r:?} ({rb:#0width$x})",
format_args!($($tt)*),
lb = l.to_bits(),
Expand Down
4 changes: 3 additions & 1 deletion libm/src/math/support/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,16 @@ pub use env::{FpResult, Round, Status};
#[allow(unused_imports)]
pub use float_traits::{DFloat, Float, HFloat, IntTy};
pub(crate) use float_traits::{f32_from_bits, f64_from_bits};
#[cfg(any(test, feature = "unstable-public-internals"))]
pub use hex_float::Hexf;
#[cfg(f16_enabled)]
#[allow(unused_imports)]
pub use hex_float::hf16;
#[cfg(f128_enabled)]
#[allow(unused_imports)]
pub use hex_float::hf128;
#[allow(unused_imports)]
pub use hex_float::{Hexf, hf32, hf64};
pub use hex_float::{hf32, hf64};
pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt};

/// Hint to the compiler that the current path is cold.
Expand Down
Loading