| //! The 16-bit brain floating-point type. | |
| #![unstable(feature = "f16b", issue = "160630")] | |
| use crate::{fmt, mem}; | |
| /// A 16-bit brain floating-point value. | |
| /// | |
| /// This type stores values using the bfloat16 encoding. It deliberately | |
| /// exposes only raw-bit construction, comparison, formatting, and lossless | |
| /// widening to [`f32`]. | |
| /// | |
| /// The 16-bit brain floating-point intends to preserve the dynamic range of | |
| /// a 32-bit floating-point value while using half the storage. It does | |
| /// this by using 8 bits for the exponent, the same as `f32`, but only | |
| /// using 7 bits for the mantissa. See [Wikipedia on bfloat16][wikipedia] for | |
| /// more information. | |
| /// | |
| /// [wikipedia]: https://en.wikipedia.org/wiki/Bfloat16_floating-point_format | |
| #[lang = "f16b"] | |
| #[doc(alias = "bf16")] // what hardware often names it | |
| #[doc(alias = "bfloat")] // LLVM's name | |
| #[doc(alias = "bfloat16")] // Wikipedia's name | |
| #[doc(alias = "bfloat16_t")] // The C++ `stdfloat` name | |
| #[allow(non_camel_case_types)] | |
| #[repr(transparent)] | |
| #[unstable(feature = "f16b", issue = "160630")] | |
| pub struct f16b(u16); | |
| #[doc(test(attr( | |
| feature(cfg_target_has_reliable_f16b), | |
| allow(internal_features, unused_features) | |
| )))] | |
| impl f16b { | |
| /// Raw transmutation from `u16`. | |
| /// | |
| /// This is currently identical to `transmute::<u16, f16b>(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. | |
| /// | |
| /// ```no_run | |
| /// #![feature(f16b)] | |
| /// # #[cfg(target_has_reliable_f16b)] { | |
| /// use core::num::f16b; | |
| /// | |
| /// let v = f16b::from_bits(0x4148); | |
| /// assert_eq!(f32::from(v), 12.5); | |
| /// # } | |
| /// ``` | |
| #[inline] | |
| #[must_use] | |
| #[unstable(feature = "f16b", issue = "160630")] | |
| pub const fn from_bits(bits: u16) -> Self { | |
| // SAFETY: `f16b` and `u16` have the same size, and every bit pattern is valid. | |
| unsafe { mem::transmute(bits) } | |
| } | |
| /// Raw transmutation to `u16`. | |
| /// | |
| /// This is currently identical to `transmute::<f16b, 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. | |
| /// | |
| /// ```no_run | |
| /// #![feature(f16b)] | |
| /// # #[cfg(target_has_reliable_f16b)] { | |
| /// use core::num::f16b; | |
| /// | |
| /// assert_eq!(f16b::from_bits(0x4148).to_bits(), 0x4148); | |
| /// # } | |
| /// ``` | |
| #[inline] | |
| #[unstable(feature = "f16b", issue = "160630")] | |
| #[must_use = "this returns the result of the operation, without modifying the original"] | |
| pub const fn to_bits(self) -> u16 { | |
| // SAFETY: `f16b` and `u16` have the same size, and every bit pattern is valid. | |
| unsafe { mem::transmute(self) } | |
| } | |
| } | |
| // FIXME(f16b) - This should be a `#[rustc_intrinsic]` using LLVM's `fpext` | |
| // with this implementation constituting the fallback. | |
| #[inline] | |
| const fn widen(value: f16b) -> f32 { | |
| f32::from_bits((value.to_bits() as u32) << 16) | |
| } | |
| #[unstable(feature = "f16b", issue = "160630")] | |
| impl Copy for f16b {} | |
| #[unstable(feature = "f16b", issue = "160630")] | |
| impl Clone for f16b { | |
| #[inline] | |
| fn clone(&self) -> Self { | |
| *self | |
| } | |
| } | |
| #[unstable(feature = "f16b", issue = "160630")] | |
| impl Default for f16b { | |
| #[inline] | |
| fn default() -> Self { | |
| Self::from_bits(0) | |
| } | |
| } | |
| #[unstable(feature = "f16b", issue = "160630")] | |
| impl PartialEq for f16b { | |
| #[inline] | |
| fn eq(&self, other: &Self) -> bool { | |
| widen(*self).eq(&widen(*other)) | |
| } | |
| } | |
| #[unstable(feature = "f16b", issue = "160630")] | |
| impl PartialOrd for f16b { | |
| #[inline] | |
| fn partial_cmp(&self, other: &Self) -> Option<crate::cmp::Ordering> { | |
| widen(*self).partial_cmp(&widen(*other)) | |
| } | |
| } | |
| #[unstable(feature = "f16b", issue = "160630")] | |
| impl From<f16b> for f32 { | |
| #[inline] | |
| fn from(value: f16b) -> Self { | |
| widen(value) | |
| } | |
| } | |
| #[unstable(feature = "f16b", issue = "160630")] | |
| impl fmt::Debug for f16b { | |
| #[inline] | |
| fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| fmt::Debug::fmt(&widen(*self), formatter) | |
| } | |
| } | |
| #[cfg(not(no_fp_fmt_parse))] | |
| #[unstable(feature = "f16b", issue = "160630")] | |
| impl fmt::LowerExp for f16b { | |
| #[inline] | |
| fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| fmt::LowerExp::fmt(&widen(*self), formatter) | |
| } | |
| } | |
| #[cfg(not(no_fp_fmt_parse))] | |
| #[unstable(feature = "f16b", issue = "160630")] | |
| impl fmt::UpperExp for f16b { | |
| #[inline] | |
| fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| fmt::UpperExp::fmt(&widen(*self), formatter) | |
| } | |
| } |