Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a Debug impl and some basic functions to f16 and f128 #123783

Merged
merged 1 commit into from
Apr 12, 2024
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
16 changes: 16 additions & 0 deletions library/core/src/fmt/float.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,3 +228,19 @@ macro_rules! floating {

floating! { f32 }
floating! { f64 }

#[stable(feature = "rust1", since = "1.0.0")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not the correct version, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have just been using the same gate as the traits on f32 and f64 for now, since most of the impl macros don't have a way to specify the gate. I think that when this is closer to stabilization I will change the macros and add a separate gate, but for now I don't think it gains much to not just match the other floats.

impl Debug for f16 {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
tgross35 marked this conversation as resolved.
Show resolved Hide resolved
write!(f, "{:#06x}", self.to_bits())
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Debug for f128 {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(f, "{:#034x}", self.to_bits())
}
}
104 changes: 104 additions & 0 deletions library/core/src/num/f128.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,110 @@

#![unstable(feature = "f128", issue = "116909")]

use crate::mem;

/// Basic mathematical constants.
#[unstable(feature = "f128", issue = "116909")]
pub mod consts {}

#[cfg(not(test))]
impl f128 {
// FIXME(f16_f128): almost everything in this `impl` is missing examples and a const
// implementation. Add these once we can run code on all platforms and have f16/f128 in CTFE.

/// Returns `true` if this value is NaN.
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
#[allow(clippy::eq_op)] // > if you intended to check if the operand is NaN, use `.is_nan()` instead :)
pub const fn is_nan(self) -> bool {
self != self
}

/// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with
/// positive sign bit and positive infinity. Note that IEEE 754 doesn't assign any
/// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
/// the bit pattern of NaNs are conserved over arithmetic operations, the result of
/// `is_sign_positive` on a NaN might produce an unexpected result in some cases.
/// See [explanation of NaN as a special value](f32) for more info.
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
pub fn is_sign_positive(self) -> bool {
!self.is_sign_negative()
}

/// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs with
/// negative sign bit and negative infinity. Note that IEEE 754 doesn't assign any
/// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
/// the bit pattern of NaNs are conserved over arithmetic operations, the result of
/// `is_sign_negative` on a NaN might produce an unexpected result in some cases.
/// See [explanation of NaN as a special value](f32) for more info.
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
pub fn is_sign_negative(self) -> bool {
// IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus
// applies to zeros and NaNs as well.
// SAFETY: This is just transmuting to get the sign bit, it's fine.
(self.to_bits() & (1 << 127)) != 0
}

/// Raw transmutation to `u128`.
///
/// This is currently identical to `transmute::<f128, u128>(self)` on all platforms.
///
/// See [`from_bits`](#method.from_bits) for some discussion of the
/// portability of this operation (there are almost no issues).
///
/// Note that this function is distinct from `as` casting, which attempts to
/// preserve the *numeric* value, and not the bitwise value.
#[inline]
#[unstable(feature = "f128", issue = "116909")]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn to_bits(self) -> u128 {
// SAFETY: `u128` is a plain old datatype so we can always... uh...
// ...look, just pretend you forgot what you just read.
// Stability concerns.
unsafe { mem::transmute(self) }
}

/// Raw transmutation from `u128`.
///
/// This is currently identical to `transmute::<u128, f128>(v)` on all platforms.
/// It turns out this is incredibly portable, for two reasons:
///
/// * Floats and Ints have the same endianness on all supported platforms.
/// * IEEE 754 very precisely specifies the bit layout of floats.
///
/// However there is one caveat: prior to the 2008 version of IEEE 754, how
/// to interpret the NaN signaling bit wasn't actually specified. Most platforms
/// (notably x86 and ARM) picked the interpretation that was ultimately
/// standardized in 2008, but some didn't (notably MIPS). As a result, all
/// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa.
///
/// Rather than trying to preserve signaling-ness cross-platform, this
/// implementation favors preserving the exact bits. This means that
/// any payloads encoded in NaNs will be preserved even if the result of
/// this method is sent over the network from an x86 machine to a MIPS one.
///
/// If the results of this method are only manipulated by the same
/// architecture that produced them, then there is no portability concern.
///
/// If the input isn't NaN, then there is no portability concern.
///
/// If you don't care about signalingness (very likely), then there is no
/// portability concern.
///
/// Note that this function is distinct from `as` casting, which attempts to
/// preserve the *numeric* value, and not the bitwise value.
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
pub fn from_bits(v: u128) -> Self {
// SAFETY: `u128 is a plain old datatype so we can always... uh...
// ...look, just pretend you forgot what you just read.
// Stability concerns.
unsafe { mem::transmute(v) }
}
}
104 changes: 104 additions & 0 deletions library/core/src/num/f16.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,110 @@

#![unstable(feature = "f16", issue = "116909")]

use crate::mem;

/// Basic mathematical constants.
#[unstable(feature = "f16", issue = "116909")]
pub mod consts {}

#[cfg(not(test))]
impl f16 {
// FIXME(f16_f128): almost everything in this `impl` is missing examples and a const
// implementation. Add these once we can run code on all platforms and have f16/f128 in CTFE.

/// Returns `true` if this value is NaN.
#[inline]
#[must_use]
#[unstable(feature = "f16", issue = "116909")]
#[allow(clippy::eq_op)] // > if you intended to check if the operand is NaN, use `.is_nan()` instead :)
pub const fn is_nan(self) -> bool {
self != self
}

/// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with
/// positive sign bit and positive infinity. Note that IEEE 754 doesn't assign any
/// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
/// the bit pattern of NaNs are conserved over arithmetic operations, the result of
/// `is_sign_positive` on a NaN might produce an unexpected result in some cases.
/// See [explanation of NaN as a special value](f32) for more info.
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
pub fn is_sign_positive(self) -> bool {
!self.is_sign_negative()
}

/// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs with
/// negative sign bit and negative infinity. Note that IEEE 754 doesn't assign any
/// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
/// the bit pattern of NaNs are conserved over arithmetic operations, the result of
/// `is_sign_negative` on a NaN might produce an unexpected result in some cases.
/// See [explanation of NaN as a special value](f32) for more info.
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
pub fn is_sign_negative(self) -> bool {
// IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus
// applies to zeros and NaNs as well.
// SAFETY: This is just transmuting to get the sign bit, it's fine.
(self.to_bits() & (1 << 15)) != 0
}

/// Raw transmutation to `u16`.
///
/// This is currently identical to `transmute::<f16, u16>(self)` on all platforms.
///
/// See [`from_bits`](#method.from_bits) for some discussion of the
/// portability of this operation (there are almost no issues).
///
/// Note that this function is distinct from `as` casting, which attempts to
/// preserve the *numeric* value, and not the bitwise value.
#[inline]
#[unstable(feature = "f16", issue = "116909")]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn to_bits(self) -> u16 {
// SAFETY: `u16` is a plain old datatype so we can always... uh...
// ...look, just pretend you forgot what you just read.
// Stability concerns.
unsafe { mem::transmute(self) }
}

/// Raw transmutation from `u16`.
///
/// This is currently identical to `transmute::<u16, f16>(v)` on all platforms.
/// It turns out this is incredibly portable, for two reasons:
///
/// * Floats and Ints have the same endianness on all supported platforms.
/// * IEEE 754 very precisely specifies the bit layout of floats.
///
/// However there is one caveat: prior to the 2008 version of IEEE 754, how
/// to interpret the NaN signaling bit wasn't actually specified. Most platforms
/// (notably x86 and ARM) picked the interpretation that was ultimately
/// standardized in 2008, but some didn't (notably MIPS). As a result, all
/// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa.
///
/// Rather than trying to preserve signaling-ness cross-platform, this
/// implementation favors preserving the exact bits. This means that
/// any payloads encoded in NaNs will be preserved even if the result of
/// this method is sent over the network from an x86 machine to a MIPS one.
///
/// If the results of this method are only manipulated by the same
/// architecture that produced them, then there is no portability concern.
///
/// If the input isn't NaN, then there is no portability concern.
///
/// If you don't care about signalingness (very likely), then there is no
/// portability concern.
///
/// Note that this function is distinct from `as` casting, which attempts to
/// preserve the *numeric* value, and not the bitwise value.
#[inline]
#[must_use]
#[unstable(feature = "f16", issue = "116909")]
pub fn from_bits(v: u16) -> Self {
// SAFETY: `u16` is a plain old datatype so we can always... uh...
// ...look, just pretend you forgot what you just read.
// Stability concerns.
unsafe { mem::transmute(v) }
}
}
Loading