/// A 16-bit floating point type implementing the [`bfloat16`] format. /// /// The [`bfloat16`] floating point format is a truncated 16-bit version of the IEEE 754 standard /// `binary32`, a.k.a [`f32`]. [`bf16`] has approximately the same dynamic range as [`f32`] by /// having a lower precision than [`f16`][crate::f16]. While [`f16`][crate::f16] has a precision of /// 11 bits, [`bf16`] has a precision of only 8 bits. /// /// Like [`f16`][crate::f16], [`bf16`] does not offer arithmetic operations as it is intended for /// compact storage rather than calculations. Operations should be performed with [`f32`] or /// higher-precision types and converted to/from [`bf16`] as necessary. /// /// [`bfloat16`]: https://en.wikipedia.org/wiki/Bfloat16_floating-point_format #[allow(non_camel_case_types)] #[derive(Clone, Copy, Default)] #[repr(transparent)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "bytemuck", derive(Zeroable, Pod))] #[cfg_attr(feature = "zerocopy", derive(AsBytes, FromBytes))] pubstruct bf16(u16);
impl bf16 { /// Constructs a [`bf16`] value from the raw bits. #[inline] pubconstfn from_bits(bits: u16) -> bf16 {
bf16(bits)
}
/// Constructs a [`bf16`] value from a 32-bit floating point value. /// /// If the 32-bit value is too large to fit, ±∞ will result. NaN values are preserved. /// Subnormal values that are too tiny to be represented will result in ±0. All other values /// are truncated and rounded to the nearest representable value. #[inline] pubfn from_f32(value: f32) -> bf16 {
bf16(convert::f32_to_bf16(value))
}
/// Constructs a [`bf16`] value from a 64-bit floating point value. /// /// If the 64-bit value is to large to fit, ±∞ will result. NaN values are preserved. /// 64-bit subnormal values are too tiny to be represented and result in ±0. Exponents that /// underflow the minimum exponent will result in subnormals or ±0. All other values are /// truncated and rounded to the nearest representable value. #[inline] pubfn from_f64(value: f64) -> bf16 {
bf16(convert::f64_to_bf16(value))
}
/// Converts a [`bf16`] into the underlying bit representation. #[inline] pubconstfn to_bits(self) -> u16 { self.0
}
/// Returns the memory representation of the underlying bit representation as a byte array in /// little-endian byte order. /// /// # Examples /// /// ```rust /// # use half::prelude::*; /// let bytes = bf16::from_f32(12.5).to_le_bytes(); /// assert_eq!(bytes, [0x48, 0x41]); /// ``` #[inline] pubconstfn to_le_bytes(self) -> [u8; 2] { self.0.to_le_bytes()
}
/// Returns the memory representation of the underlying bit representation as a byte array in /// big-endian (network) byte order. /// /// # Examples /// /// ```rust /// # use half::prelude::*; /// let bytes = bf16::from_f32(12.5).to_be_bytes(); /// assert_eq!(bytes, [0x41, 0x48]); /// ``` #[inline] pubconstfn to_be_bytes(self) -> [u8; 2] { self.0.to_be_bytes()
}
/// Returns the memory representation of the underlying bit representation as a byte array in /// native byte order. /// /// As the target platform's native endianness is used, portable code should use /// [`to_be_bytes`][bf16::to_be_bytes] or [`to_le_bytes`][bf16::to_le_bytes], as appropriate, /// instead. /// /// # Examples /// /// ```rust /// # use half::prelude::*; /// let bytes = bf16::from_f32(12.5).to_ne_bytes(); /// assert_eq!(bytes, if cfg!(target_endian = "big") { /// [0x41, 0x48] /// } else { /// [0x48, 0x41] /// }); /// ``` #[inline] pubconstfn to_ne_bytes(self) -> [u8; 2] { self.0.to_ne_bytes()
}
/// Creates a floating point value from its representation as a byte array in little endian. /// /// # Examples /// /// ```rust /// # use half::prelude::*; /// let value = bf16::from_le_bytes([0x48, 0x41]); /// assert_eq!(value, bf16::from_f32(12.5)); /// ``` #[inline] pubconstfn from_le_bytes(bytes: [u8; 2]) -> bf16 {
bf16::from_bits(u16::from_le_bytes(bytes))
}
/// Creates a floating point value from its representation as a byte array in big endian. /// /// # Examples /// /// ```rust /// # use half::prelude::*; /// let value = bf16::from_be_bytes([0x41, 0x48]); /// assert_eq!(value, bf16::from_f32(12.5)); /// ``` #[inline] pubconstfn from_be_bytes(bytes: [u8; 2]) -> bf16 {
bf16::from_bits(u16::from_be_bytes(bytes))
}
/// Creates a floating point value from its representation as a byte array in native endian. /// /// As the target platform's native endianness is used, portable code likely wants to use /// [`from_be_bytes`][bf16::from_be_bytes] or [`from_le_bytes`][bf16::from_le_bytes], as /// appropriate instead. /// /// # Examples /// /// ```rust /// # use half::prelude::*; /// let value = bf16::from_ne_bytes(if cfg!(target_endian = "big") { /// [0x41, 0x48] /// } else { /// [0x48, 0x41] /// }); /// assert_eq!(value, bf16::from_f32(12.5)); /// ``` #[inline] pubconstfn from_ne_bytes(bytes: [u8; 2]) -> bf16 {
bf16::from_bits(u16::from_ne_bytes(bytes))
}
/// Converts a [`bf16`] value into an [`f32`] value. /// /// This conversion is lossless as all values can be represented exactly in [`f32`]. #[inline] pubfn to_f32(self) -> f32 {
convert::bf16_to_f32(self.0)
}
/// Converts a [`bf16`] value into an [`f64`] value. /// /// This conversion is lossless as all values can be represented exactly in [`f64`]. #[inline] pubfn to_f64(self) -> f64 {
convert::bf16_to_f64(self.0)
}
/// Returns `true` if this value is NaN and `false` otherwise. /// /// # Examples /// /// ```rust /// # use half::prelude::*; /// /// let nan = bf16::NAN; /// let f = bf16::from_f32(7.0_f32); /// /// assert!(nan.is_nan()); /// assert!(!f.is_nan()); /// ``` #[inline] pubconstfn is_nan(self) -> bool { self.0 & 0x7FFFu16 > 0x7F80u16
}
/// Returns `true` if this value is ±∞ and `false` otherwise. /// /// # Examples /// /// ```rust /// # use half::prelude::*; /// /// let f = bf16::from_f32(7.0f32); /// let inf = bf16::INFINITY; /// let neg_inf = bf16::NEG_INFINITY; /// let nan = bf16::NAN; /// /// assert!(!f.is_infinite()); /// assert!(!nan.is_infinite()); /// /// assert!(inf.is_infinite()); /// assert!(neg_inf.is_infinite()); /// ``` #[inline] pubconstfn is_infinite(self) -> bool { self.0 & 0x7FFFu16 == 0x7F80u16
}
/// Returns `true` if this number is neither infinite nor NaN. /// /// # Examples /// /// ```rust /// # use half::prelude::*; /// /// let f = bf16::from_f32(7.0f32); /// let inf = bf16::INFINITY; /// let neg_inf = bf16::NEG_INFINITY; /// let nan = bf16::NAN; /// /// assert!(f.is_finite()); /// /// assert!(!nan.is_finite()); /// assert!(!inf.is_finite()); /// assert!(!neg_inf.is_finite()); /// ``` #[inline] pubconstfn is_finite(self) -> bool { self.0 & 0x7F80u16 != 0x7F80u16
}
/// Returns `true` if the number is neither zero, infinite, subnormal, or NaN. /// /// # Examples /// /// ```rust /// # use half::prelude::*; /// /// let min = bf16::MIN_POSITIVE; /// let max = bf16::MAX; /// let lower_than_min = bf16::from_f32(1.0e-39_f32); /// let zero = bf16::from_f32(0.0_f32); /// /// assert!(min.is_normal()); /// assert!(max.is_normal()); /// /// assert!(!zero.is_normal()); /// assert!(!bf16::NAN.is_normal()); /// assert!(!bf16::INFINITY.is_normal()); /// // Values between 0 and `min` are subnormal. /// assert!(!lower_than_min.is_normal()); /// ``` #[inline] pubconstfn is_normal(self) -> bool { let exp = self.0 & 0x7F80u16;
exp != 0x7F80u16 && exp != 0
}
/// Returns the floating point category of the number. /// /// If only one property is going to be tested, it is generally faster to use the specific /// predicate instead. /// /// # Examples /// /// ```rust /// use std::num::FpCategory; /// # use half::prelude::*; /// /// let num = bf16::from_f32(12.4_f32); /// let inf = bf16::INFINITY; /// /// assert_eq!(num.classify(), FpCategory::Normal); /// assert_eq!(inf.classify(), FpCategory::Infinite); /// ``` pubconstfn classify(self) -> FpCategory { let exp = self.0 & 0x7F80u16; let man = self.0 & 0x007Fu16; match (exp, man) {
(0, 0) => FpCategory::Zero,
(0, _) => FpCategory::Subnormal,
(0x7F80u16, 0) => FpCategory::Infinite,
(0x7F80u16, _) => FpCategory::Nan,
_ => FpCategory::Normal,
}
}
/// Returns a number that represents the sign of `self`. /// /// * 1.0 if the number is positive, +0.0 or [`INFINITY`][bf16::INFINITY] /// * −1.0 if the number is negative, −0.0` or [`NEG_INFINITY`][bf16::NEG_INFINITY] /// * [`NAN`][bf16::NAN] if the number is NaN /// /// # Examples /// /// ```rust /// # use half::prelude::*; /// /// let f = bf16::from_f32(3.5_f32); /// /// assert_eq!(f.signum(), bf16::from_f32(1.0)); /// assert_eq!(bf16::NEG_INFINITY.signum(), bf16::from_f32(-1.0)); /// /// assert!(bf16::NAN.signum().is_nan()); /// ``` pubconstfn signum(self) -> bf16 { ifself.is_nan() { self
} elseifself.0 & 0x8000u16 != 0 { Self::NEG_ONE
} else { Self::ONE
}
}
/// Returns `true` if and only if `self` has a positive sign, including +0.0, NaNs with a /// positive sign bit and +∞. /// /// # Examples /// /// ```rust /// # use half::prelude::*; /// /// let nan = bf16::NAN; /// let f = bf16::from_f32(7.0_f32); /// let g = bf16::from_f32(-7.0_f32); /// /// assert!(f.is_sign_positive()); /// assert!(!g.is_sign_positive()); /// // NaN can be either positive or negative /// assert!(nan.is_sign_positive() != nan.is_sign_negative()); /// ``` #[inline] pubconstfn is_sign_positive(self) -> bool { self.0 & 0x8000u16 == 0
}
/// Returns `true` if and only if `self` has a negative sign, including −0.0, NaNs with a /// negative sign bit and −∞. /// /// # Examples /// /// ```rust /// # use half::prelude::*; /// /// let nan = bf16::NAN; /// let f = bf16::from_f32(7.0f32); /// let g = bf16::from_f32(-7.0f32); /// /// assert!(!f.is_sign_negative()); /// assert!(g.is_sign_negative()); /// // NaN can be either positive or negative /// assert!(nan.is_sign_positive() != nan.is_sign_negative()); /// ``` #[inline] pubconstfn is_sign_negative(self) -> bool { self.0 & 0x8000u16 != 0
}
/// Returns a number composed of the magnitude of `self` and the sign of `sign`. /// /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise equal to `-self`. /// If `self` is NaN, then NaN with the sign of `sign` is returned. /// /// # Examples /// /// ``` /// # use half::prelude::*; /// let f = bf16::from_f32(3.5); /// /// assert_eq!(f.copysign(bf16::from_f32(0.42)), bf16::from_f32(3.5)); /// assert_eq!(f.copysign(bf16::from_f32(-0.42)), bf16::from_f32(-3.5)); /// assert_eq!((-f).copysign(bf16::from_f32(0.42)), bf16::from_f32(3.5)); /// assert_eq!((-f).copysign(bf16::from_f32(-0.42)), bf16::from_f32(-3.5)); /// /// assert!(bf16::NAN.copysign(bf16::from_f32(1.0)).is_nan()); /// ``` #[inline] pubconstfn copysign(self, sign: bf16) -> bf16 {
bf16((sign.0 & 0x8000u16) | (self.0 & 0x7FFFu16))
}
/// Returns the maximum of the two numbers. /// /// If one of the arguments is NaN, then the other argument is returned. /// /// # Examples /// /// ``` /// # use half::prelude::*; /// let x = bf16::from_f32(1.0); /// let y = bf16::from_f32(2.0); /// /// assert_eq!(x.max(y), y); /// ``` #[inline] pubfn max(self, other: bf16) -> bf16 { if other > self && !other.is_nan() {
other
} else { self
}
}
/// Returns the minimum of the two numbers. /// /// If one of the arguments is NaN, then the other argument is returned. /// /// # Examples /// /// ``` /// # use half::prelude::*; /// let x = bf16::from_f32(1.0); /// let y = bf16::from_f32(2.0); /// /// assert_eq!(x.min(y), x); /// ``` #[inline] pubfn min(self, other: bf16) -> bf16 { if other < self && !other.is_nan() {
other
} else { self
}
}
/// Restrict a value to a certain interval unless it is NaN. /// /// Returns `max` if `self` is greater than `max`, and `min` if `self` is less than `min`. /// Otherwise this returns `self`. /// /// Note that this function returns NaN if the initial value was NaN as well. /// /// # Panics /// Panics if `min > max`, `min` is NaN, or `max` is NaN. /// /// # Examples /// /// ``` /// # use half::prelude::*; /// assert!(bf16::from_f32(-3.0).clamp(bf16::from_f32(-2.0), bf16::from_f32(1.0)) == bf16::from_f32(-2.0)); /// assert!(bf16::from_f32(0.0).clamp(bf16::from_f32(-2.0), bf16::from_f32(1.0)) == bf16::from_f32(0.0)); /// assert!(bf16::from_f32(2.0).clamp(bf16::from_f32(-2.0), bf16::from_f32(1.0)) == bf16::from_f32(1.0)); /// assert!(bf16::NAN.clamp(bf16::from_f32(-2.0), bf16::from_f32(1.0)).is_nan()); /// ``` #[inline] pubfn clamp(self, min: bf16, max: bf16) -> bf16 {
assert!(min <= max); letmut x = self; if x < min {
x = min;
} if x > max {
x = max;
}
x
}
/// Approximate number of [`bf16`] significant digits in base 10 pubconst DIGITS: u32 = 2; /// [`bf16`] /// [machine epsilon](https://en.wikipedia.org/wiki/Machine_epsilon) value /// /// This is the difference between 1.0 and the next largest representable number. pubconst EPSILON: bf16 = bf16(0x3C00u16); /// [`bf16`] positive Infinity (+∞) pubconst INFINITY: bf16 = bf16(0x7F80u16); /// Number of [`bf16`] significant digits in base 2 pubconst MANTISSA_DIGITS: u32 = 8; /// Largest finite [`bf16`] value pubconst MAX: bf16 = bf16(0x7F7F); /// Maximum possible [`bf16`] power of 10 exponent pubconst MAX_10_EXP: i32 = 38; /// Maximum possible [`bf16`] power of 2 exponent pubconst MAX_EXP: i32 = 128; /// Smallest finite [`bf16`] value pubconst MIN: bf16 = bf16(0xFF7F); /// Minimum possible normal [`bf16`] power of 10 exponent pubconst MIN_10_EXP: i32 = -37; /// One greater than the minimum possible normal [`bf16`] power of 2 exponent pubconst MIN_EXP: i32 = -125; /// Smallest positive normal [`bf16`] value pubconst MIN_POSITIVE: bf16 = bf16(0x0080u16); /// [`bf16`] Not a Number (NaN) pubconst NAN: bf16 = bf16(0x7FC0u16); /// [`bf16`] negative infinity (-∞). pubconst NEG_INFINITY: bf16 = bf16(0xFF80u16); /// The radix or base of the internal representation of [`bf16`] pubconst RADIX: u32 = 2;
/// Minimum positive subnormal [`bf16`] value pubconst MIN_POSITIVE_SUBNORMAL: bf16 = bf16(0x0001u16); /// Maximum subnormal [`bf16`] value pubconst MAX_SUBNORMAL: bf16 = bf16(0x007Fu16);
#[allow(
clippy::cognitive_complexity,
clippy::float_cmp,
clippy::neg_cmp_op_on_partial_ord
)] #[cfg(test)] mod test { usesuper::*; use core::cmp::Ordering; #[cfg(feature = "num-traits")] use num_traits::{AsPrimitive, FromPrimitive, ToPrimitive}; use quickcheck_macros::quickcheck;
#[cfg(feature = "num-traits")] #[test] fn as_primitive() { let two = bf16::from_f32(2.0);
assert_eq!(<i32 as AsPrimitive<bf16>>::as_(2), two);
assert_eq!(<bf16 as AsPrimitive<i32>>::as_(two), 2);
assert_eq!(<f32 as AsPrimitive<bf16>>::as_(2.0), two);
assert_eq!(<bf16 as AsPrimitive<f32>>::as_(two), 2.0);
assert_eq!(<f64 as AsPrimitive<bf16>>::as_(2.0), two);
assert_eq!(<bf16 as AsPrimitive<f64>>::as_(two), 2.0);
}
#[cfg(feature = "num-traits")] #[test] fn to_primitive() { let two = bf16::from_f32(2.0);
assert_eq!(ToPrimitive::to_i32(&two).unwrap(), 2i32);
assert_eq!(ToPrimitive::to_f32(&two).unwrap(), 2.0f32);
assert_eq!(ToPrimitive::to_f64(&two).unwrap(), 2.0f64);
}
#[cfg(feature = "num-traits")] #[test] fn from_primitive() { let two = bf16::from_f32(2.0);
assert_eq!(<bf16 as FromPrimitive>::from_i32(2).unwrap(), two);
assert_eq!(<bf16 as FromPrimitive>::from_f32(2.0).unwrap(), two);
assert_eq!(<bf16 as FromPrimitive>::from_f64(2.0).unwrap(), two);
}
#[test] fn test_bf16_consts_from_f32() { let one = bf16::from_f32(1.0); let zero = bf16::from_f32(0.0); let neg_zero = bf16::from_f32(-0.0); let neg_one = bf16::from_f32(-1.0); let inf = bf16::from_f32(core::f32::INFINITY); let neg_inf = bf16::from_f32(core::f32::NEG_INFINITY); let nan = bf16::from_f32(core::f32::NAN);
let e = bf16::from_f32(core::f32::consts::E); let pi = bf16::from_f32(core::f32::consts::PI); let frac_1_pi = bf16::from_f32(core::f32::consts::FRAC_1_PI); let frac_1_sqrt_2 = bf16::from_f32(core::f32::consts::FRAC_1_SQRT_2); let frac_2_pi = bf16::from_f32(core::f32::consts::FRAC_2_PI); let frac_2_sqrt_pi = bf16::from_f32(core::f32::consts::FRAC_2_SQRT_PI); let frac_pi_2 = bf16::from_f32(core::f32::consts::FRAC_PI_2); let frac_pi_3 = bf16::from_f32(core::f32::consts::FRAC_PI_3); let frac_pi_4 = bf16::from_f32(core::f32::consts::FRAC_PI_4); let frac_pi_6 = bf16::from_f32(core::f32::consts::FRAC_PI_6); let frac_pi_8 = bf16::from_f32(core::f32::consts::FRAC_PI_8); let ln_10 = bf16::from_f32(core::f32::consts::LN_10); let ln_2 = bf16::from_f32(core::f32::consts::LN_2); let log10_e = bf16::from_f32(core::f32::consts::LOG10_E); // core::f32::consts::LOG10_2 requires rustc 1.43.0 let log10_2 = bf16::from_f32(2f32.log10()); let log2_e = bf16::from_f32(core::f32::consts::LOG2_E); // core::f32::consts::LOG2_10 requires rustc 1.43.0 let log2_10 = bf16::from_f32(10f32.log2()); let sqrt_2 = bf16::from_f32(core::f32::consts::SQRT_2);
#[test] fn test_bf16_consts_from_f64() { let one = bf16::from_f64(1.0); let zero = bf16::from_f64(0.0); let neg_zero = bf16::from_f64(-0.0); let inf = bf16::from_f64(core::f64::INFINITY); let neg_inf = bf16::from_f64(core::f64::NEG_INFINITY); let nan = bf16::from_f64(core::f64::NAN);
let e = bf16::from_f64(core::f64::consts::E); let pi = bf16::from_f64(core::f64::consts::PI); let frac_1_pi = bf16::from_f64(core::f64::consts::FRAC_1_PI); let frac_1_sqrt_2 = bf16::from_f64(core::f64::consts::FRAC_1_SQRT_2); let frac_2_pi = bf16::from_f64(core::f64::consts::FRAC_2_PI); let frac_2_sqrt_pi = bf16::from_f64(core::f64::consts::FRAC_2_SQRT_PI); let frac_pi_2 = bf16::from_f64(core::f64::consts::FRAC_PI_2); let frac_pi_3 = bf16::from_f64(core::f64::consts::FRAC_PI_3); let frac_pi_4 = bf16::from_f64(core::f64::consts::FRAC_PI_4); let frac_pi_6 = bf16::from_f64(core::f64::consts::FRAC_PI_6); let frac_pi_8 = bf16::from_f64(core::f64::consts::FRAC_PI_8); let ln_10 = bf16::from_f64(core::f64::consts::LN_10); let ln_2 = bf16::from_f64(core::f64::consts::LN_2); let log10_e = bf16::from_f64(core::f64::consts::LOG10_E); // core::f64::consts::LOG10_2 requires rustc 1.43.0 let log10_2 = bf16::from_f64(2f64.log10()); let log2_e = bf16::from_f64(core::f64::consts::LOG2_E); // core::f64::consts::LOG2_10 requires rustc 1.43.0 let log2_10 = bf16::from_f64(10f64.log2()); let sqrt_2 = bf16::from_f64(core::f64::consts::SQRT_2);
#[test] fn test_nan_conversion_to_smaller() { let nan64 = f64::from_bits(0x7FF0_0000_0000_0001u64); let neg_nan64 = f64::from_bits(0xFFF0_0000_0000_0001u64); let nan32 = f32::from_bits(0x7F80_0001u32); let neg_nan32 = f32::from_bits(0xFF80_0001u32); let nan32_from_64 = nan64 as f32; let neg_nan32_from_64 = neg_nan64 as f32; let nan16_from_64 = bf16::from_f64(nan64); let neg_nan16_from_64 = bf16::from_f64(neg_nan64); let nan16_from_32 = bf16::from_f32(nan32); let neg_nan16_from_32 = bf16::from_f32(neg_nan32);
#[test] fn test_nan_conversion_to_larger() { let nan16 = bf16::from_bits(0x7F81u16); let neg_nan16 = bf16::from_bits(0xFF81u16); let nan32 = f32::from_bits(0x7F80_0001u32); let neg_nan32 = f32::from_bits(0xFF80_0001u32); let nan32_from_16 = f32::from(nan16); let neg_nan32_from_16 = f32::from(neg_nan16); let nan64_from_16 = f64::from(nan16); let neg_nan64_from_16 = f64::from(neg_nan16); let nan64_from_32 = f64::from(nan32); let neg_nan64_from_32 = f64::from(neg_nan32);
#[test] fn test_bf16_to_f32() { let f = bf16::from_f32(7.0);
assert_eq!(f.to_f32(), 7.0f32);
// 7.1 is NOT exactly representable in 16-bit, it's rounded let f = bf16::from_f32(7.1); let diff = (f.to_f32() - 7.1f32).abs(); // diff must be <= 4 * EPSILON, as 7 has two more significant bits than 1
assert!(diff <= 4.0 * bf16::EPSILON.to_f32());
let tiny32 = f32::from_bits(0x0001_0000u32);
assert_eq!(bf16::from_bits(0x0001).to_f32(), tiny32);
assert_eq!(bf16::from_bits(0x0005).to_f32(), 5.0 * tiny32);
#[test] fn test_bf16_to_f64() { let f = bf16::from_f64(7.0);
assert_eq!(f.to_f64(), 7.0f64);
// 7.1 is NOT exactly representable in 16-bit, it's rounded let f = bf16::from_f64(7.1); let diff = (f.to_f64() - 7.1f64).abs(); // diff must be <= 4 * EPSILON, as 7 has two more significant bits than 1
assert!(diff <= 4.0 * bf16::EPSILON.to_f64());
let tiny64 = 2.0f64.powi(-133);
assert_eq!(bf16::from_bits(0x0001).to_f64(), tiny64);
assert_eq!(bf16::from_bits(0x0005).to_f64(), 5.0 * tiny64);
#[test] fn test_comparisons() { let zero = bf16::from_f64(0.0); let one = bf16::from_f64(1.0); let neg_zero = bf16::from_f64(-0.0); let neg_one = bf16::from_f64(-1.0);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.