/// A 16-bit floating point type implementing the IEEE 754-2008 standard [`binary16`] a.k.a `half` /// format. /// /// This 16-bit floating point type is intended for efficient storage where the full range and /// precision of a larger floating point value is not required. Because [`f16`] is primarily for /// efficient storage, floating point operations such as addition, multiplication, etc. are not /// implemented. Operations should be performed with [`f32`] or higher-precision types and converted /// to/from [`f16`] as necessary. /// /// [`binary16`]: https://en.wikipedia.org/wiki/Half-precision_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 f16(u16);
#[doc(hidden)] #[deprecated(
since = "1.4.0",
note = "all constants moved to associated constants of `f16`"
)] pubmod consts { usesuper::f16;
impl f16 { /// Constructs a 16-bit floating point value from the raw bits. #[inline] pubconstfn from_bits(bits: u16) -> f16 {
f16(bits)
}
/// Constructs a 16-bit floating point value from a 32-bit floating point value. /// /// If the 32-bit value is to large to fit in 16-bits, ±∞ will result. NaN values are /// preserved. 32-bit subnormal values are too tiny to be represented in 16-bits and result in /// ±0. Exponents that underflow the minimum 16-bit exponent will result in 16-bit subnormals /// or ±0. All other values are truncated and rounded to the nearest representable 16-bit /// value. #[inline] pubfn from_f32(value: f32) -> f16 {
f16(convert::f32_to_f16(value))
}
/// Constructs a 16-bit floating point value from a 64-bit floating point value. /// /// If the 64-bit value is to large to fit in 16-bits, ±∞ will result. NaN values are /// preserved. 64-bit subnormal values are too tiny to be represented in 16-bits and result in /// ±0. Exponents that underflow the minimum 16-bit exponent will result in 16-bit subnormals /// or ±0. All other values are truncated and rounded to the nearest representable 16-bit /// value. #[inline] pubfn from_f64(value: f64) -> f16 {
f16(convert::f64_to_f16(value))
}
/// Converts a [`f16`] 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 = f16::from_f32(12.5).to_le_bytes(); /// assert_eq!(bytes, [0x40, 0x4A]); /// ``` #[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 = f16::from_f32(12.5).to_be_bytes(); /// assert_eq!(bytes, [0x4A, 0x40]); /// ``` #[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`][Self::to_be_bytes] or [`to_le_bytes`][Self::to_le_bytes], as appropriate, /// instead. /// /// # Examples /// /// ```rust /// # use half::prelude::*; /// let bytes = f16::from_f32(12.5).to_ne_bytes(); /// assert_eq!(bytes, if cfg!(target_endian = "big") { /// [0x4A, 0x40] /// } else { /// [0x40, 0x4A] /// }); /// ``` #[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 = f16::from_le_bytes([0x40, 0x4A]); /// assert_eq!(value, f16::from_f32(12.5)); /// ``` #[inline] pubconstfn from_le_bytes(bytes: [u8; 2]) -> f16 {
f16::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 = f16::from_be_bytes([0x4A, 0x40]); /// assert_eq!(value, f16::from_f32(12.5)); /// ``` #[inline] pubconstfn from_be_bytes(bytes: [u8; 2]) -> f16 {
f16::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`][Self::from_be_bytes] or [`from_le_bytes`][Self::from_le_bytes], as /// appropriate instead. /// /// # Examples /// /// ```rust /// # use half::prelude::*; /// let value = f16::from_ne_bytes(if cfg!(target_endian = "big") { /// [0x4A, 0x40] /// } else { /// [0x40, 0x4A] /// }); /// assert_eq!(value, f16::from_f32(12.5)); /// ``` #[inline] pubconstfn from_ne_bytes(bytes: [u8; 2]) -> f16 {
f16::from_bits(u16::from_ne_bytes(bytes))
}
/// Converts a [`f16`] value into a `f32` value. /// /// This conversion is lossless as all 16-bit floating point values can be represented exactly /// in 32-bit floating point. #[inline] pubfn to_f32(self) -> f32 {
convert::f16_to_f32(self.0)
}
/// Converts a [`f16`] value into a `f64` value. /// /// This conversion is lossless as all 16-bit floating point values can be represented exactly /// in 64-bit floating point. #[inline] pubfn to_f64(self) -> f64 {
convert::f16_to_f64(self.0)
}
/// Returns `true` if this value is `NaN` and `false` otherwise. /// /// # Examples /// /// ```rust /// # use half::prelude::*; /// /// let nan = f16::NAN; /// let f = f16::from_f32(7.0_f32); /// /// assert!(nan.is_nan()); /// assert!(!f.is_nan()); /// ``` #[inline] pubconstfn is_nan(self) -> bool { self.0 & 0x7FFFu16 > 0x7C00u16
}
/// Returns `true` if this value is ±∞ and `false`. /// otherwise. /// /// # Examples /// /// ```rust /// # use half::prelude::*; /// /// let f = f16::from_f32(7.0f32); /// let inf = f16::INFINITY; /// let neg_inf = f16::NEG_INFINITY; /// let nan = f16::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 == 0x7C00u16
}
/// Returns `true` if this number is neither infinite nor `NaN`. /// /// # Examples /// /// ```rust /// # use half::prelude::*; /// /// let f = f16::from_f32(7.0f32); /// let inf = f16::INFINITY; /// let neg_inf = f16::NEG_INFINITY; /// let nan = f16::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 & 0x7C00u16 != 0x7C00u16
}
/// Returns `true` if the number is neither zero, infinite, subnormal, or `NaN`. /// /// # Examples /// /// ```rust /// # use half::prelude::*; /// /// let min = f16::MIN_POSITIVE; /// let max = f16::MAX; /// let lower_than_min = f16::from_f32(1.0e-10_f32); /// let zero = f16::from_f32(0.0_f32); /// /// assert!(min.is_normal()); /// assert!(max.is_normal()); /// /// assert!(!zero.is_normal()); /// assert!(!f16::NAN.is_normal()); /// assert!(!f16::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 & 0x7C00u16;
exp != 0x7C00u16 && 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 = f16::from_f32(12.4_f32); /// let inf = f16::INFINITY; /// /// assert_eq!(num.classify(), FpCategory::Normal); /// assert_eq!(inf.classify(), FpCategory::Infinite); /// ``` pubconstfn classify(self) -> FpCategory { let exp = self.0 & 0x7C00u16; let man = self.0 & 0x03FFu16; match (exp, man) {
(0, 0) => FpCategory::Zero,
(0, _) => FpCategory::Subnormal,
(0x7C00u16, 0) => FpCategory::Infinite,
(0x7C00u16, _) => FpCategory::Nan,
_ => FpCategory::Normal,
}
}
/// Returns a number that represents the sign of `self`. /// /// * `1.0` if the number is positive, `+0.0` or [`INFINITY`][f16::INFINITY] /// * `-1.0` if the number is negative, `-0.0` or [`NEG_INFINITY`][f16::NEG_INFINITY] /// * [`NAN`][f16::NAN] if the number is `NaN` /// /// # Examples /// /// ```rust /// # use half::prelude::*; /// /// let f = f16::from_f32(3.5_f32); /// /// assert_eq!(f.signum(), f16::from_f32(1.0)); /// assert_eq!(f16::NEG_INFINITY.signum(), f16::from_f32(-1.0)); /// /// assert!(f16::NAN.signum().is_nan()); /// ``` pubconstfn signum(self) -> f16 { 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 = f16::NAN; /// let f = f16::from_f32(7.0_f32); /// let g = f16::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 = f16::NAN; /// let f = f16::from_f32(7.0f32); /// let g = f16::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 = f16::from_f32(3.5); /// /// assert_eq!(f.copysign(f16::from_f32(0.42)), f16::from_f32(3.5)); /// assert_eq!(f.copysign(f16::from_f32(-0.42)), f16::from_f32(-3.5)); /// assert_eq!((-f).copysign(f16::from_f32(0.42)), f16::from_f32(3.5)); /// assert_eq!((-f).copysign(f16::from_f32(-0.42)), f16::from_f32(-3.5)); /// /// assert!(f16::NAN.copysign(f16::from_f32(1.0)).is_nan()); /// ``` #[inline] pubconstfn copysign(self, sign: f16) -> f16 {
f16((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 = f16::from_f32(1.0); /// let y = f16::from_f32(2.0); /// /// assert_eq!(x.max(y), y); /// ``` #[inline] pubfn max(self, other: f16) -> f16 { 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 = f16::from_f32(1.0); /// let y = f16::from_f32(2.0); /// /// assert_eq!(x.min(y), x); /// ``` #[inline] pubfn min(self, other: f16) -> f16 { 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!(f16::from_f32(-3.0).clamp(f16::from_f32(-2.0), f16::from_f32(1.0)) == f16::from_f32(-2.0)); /// assert!(f16::from_f32(0.0).clamp(f16::from_f32(-2.0), f16::from_f32(1.0)) == f16::from_f32(0.0)); /// assert!(f16::from_f32(2.0).clamp(f16::from_f32(-2.0), f16::from_f32(1.0)) == f16::from_f32(1.0)); /// assert!(f16::NAN.clamp(f16::from_f32(-2.0), f16::from_f32(1.0)).is_nan()); /// ``` #[inline] pubfn clamp(self, min: f16, max: f16) -> f16 {
assert!(min <= max); letmut x = self; if x < min {
x = min;
} if x > max {
x = max;
}
x
}
/// Approximate number of [`f16`] significant digits in base 10 pubconst DIGITS: u32 = 3; /// [`f16`] /// [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: f16 = f16(0x1400u16); /// [`f16`] positive Infinity (+∞) pubconst INFINITY: f16 = f16(0x7C00u16); /// Number of [`f16`] significant digits in base 2 pubconst MANTISSA_DIGITS: u32 = 11; /// Largest finite [`f16`] value pubconst MAX: f16 = f16(0x7BFF); /// Maximum possible [`f16`] power of 10 exponent pubconst MAX_10_EXP: i32 = 4; /// Maximum possible [`f16`] power of 2 exponent pubconst MAX_EXP: i32 = 16; /// Smallest finite [`f16`] value pubconst MIN: f16 = f16(0xFBFF); /// Minimum possible normal [`f16`] power of 10 exponent pubconst MIN_10_EXP: i32 = -4; /// One greater than the minimum possible normal [`f16`] power of 2 exponent pubconst MIN_EXP: i32 = -13; /// Smallest positive normal [`f16`] value pubconst MIN_POSITIVE: f16 = f16(0x0400u16); /// [`f16`] Not a Number (NaN) pubconst NAN: f16 = f16(0x7E00u16); /// [`f16`] negative infinity (-∞) pubconst NEG_INFINITY: f16 = f16(0xFC00u16); /// The radix or base of the internal representation of [`f16`] pubconst RADIX: u32 = 2;
/// Minimum positive subnormal [`f16`] value pubconst MIN_POSITIVE_SUBNORMAL: f16 = f16(0x0001u16); /// Maximum subnormal [`f16`] value pubconst MAX_SUBNORMAL: f16 = f16(0x03FFu16);
#[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 = f16::from_f32(2.0);
assert_eq!(<i32 as AsPrimitive<f16>>::as_(2), two);
assert_eq!(<f16 as AsPrimitive<i32>>::as_(two), 2);
assert_eq!(<f32 as AsPrimitive<f16>>::as_(2.0), two);
assert_eq!(<f16 as AsPrimitive<f32>>::as_(two), 2.0);
assert_eq!(<f64 as AsPrimitive<f16>>::as_(2.0), two);
assert_eq!(<f16 as AsPrimitive<f64>>::as_(two), 2.0);
}
#[cfg(feature = "num-traits")] #[test] fn to_primitive() { let two = f16::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 = f16::from_f32(2.0);
assert_eq!(<f16 as FromPrimitive>::from_i32(2).unwrap(), two);
assert_eq!(<f16 as FromPrimitive>::from_f32(2.0).unwrap(), two);
assert_eq!(<f16 as FromPrimitive>::from_f64(2.0).unwrap(), two);
}
#[test] fn test_f16_consts() { // DIGITS let digits = ((f16::MANTISSA_DIGITS as f32 - 1.0) * 2f32.log10()).floor() as u32;
assert_eq!(f16::DIGITS, digits); // sanity check to show test is good let digits32 = ((core::f32::MANTISSA_DIGITS as f32 - 1.0) * 2f32.log10()).floor() as u32;
assert_eq!(core::f32::DIGITS, digits32);
// EPSILON let one = f16::from_f32(1.0); let one_plus_epsilon = f16::from_bits(one.to_bits() + 1); let epsilon = f16::from_f32(one_plus_epsilon.to_f32() - 1.0);
assert_eq!(f16::EPSILON, epsilon); // sanity check to show test is good let one_plus_epsilon32 = f32::from_bits(1.0f32.to_bits() + 1); let epsilon32 = one_plus_epsilon32 - 1f32;
assert_eq!(core::f32::EPSILON, epsilon32);
// MAX, MIN and MIN_POSITIVE let max = f16::from_bits(f16::INFINITY.to_bits() - 1); let min = f16::from_bits(f16::NEG_INFINITY.to_bits() - 1); let min_pos = f16::from_f32(2f32.powi(f16::MIN_EXP - 1));
assert_eq!(f16::MAX, max);
assert_eq!(f16::MIN, min);
assert_eq!(f16::MIN_POSITIVE, min_pos); // sanity check to show test is good let max32 = f32::from_bits(core::f32::INFINITY.to_bits() - 1); let min32 = f32::from_bits(core::f32::NEG_INFINITY.to_bits() - 1); let min_pos32 = 2f32.powi(core::f32::MIN_EXP - 1);
assert_eq!(core::f32::MAX, max32);
assert_eq!(core::f32::MIN, min32);
assert_eq!(core::f32::MIN_POSITIVE, min_pos32);
// MIN_10_EXP and MAX_10_EXP let ten_to_min = 10f32.powi(f16::MIN_10_EXP);
assert!(ten_to_min / 10.0 < f16::MIN_POSITIVE.to_f32());
assert!(ten_to_min > f16::MIN_POSITIVE.to_f32()); let ten_to_max = 10f32.powi(f16::MAX_10_EXP);
assert!(ten_to_max < f16::MAX.to_f32());
assert!(ten_to_max * 10.0 > f16::MAX.to_f32()); // sanity check to show test is good let ten_to_min32 = 10f64.powi(core::f32::MIN_10_EXP);
assert!(ten_to_min32 / 10.0 < f64::from(core::f32::MIN_POSITIVE));
assert!(ten_to_min32 > f64::from(core::f32::MIN_POSITIVE)); let ten_to_max32 = 10f64.powi(core::f32::MAX_10_EXP);
assert!(ten_to_max32 < f64::from(core::f32::MAX));
assert!(ten_to_max32 * 10.0 > f64::from(core::f32::MAX));
}
#[test] fn test_f16_consts_from_f32() { let one = f16::from_f32(1.0); let zero = f16::from_f32(0.0); let neg_zero = f16::from_f32(-0.0); let neg_one = f16::from_f32(-1.0); let inf = f16::from_f32(core::f32::INFINITY); let neg_inf = f16::from_f32(core::f32::NEG_INFINITY); let nan = f16::from_f32(core::f32::NAN);
let e = f16::from_f32(core::f32::consts::E); let pi = f16::from_f32(core::f32::consts::PI); let frac_1_pi = f16::from_f32(core::f32::consts::FRAC_1_PI); let frac_1_sqrt_2 = f16::from_f32(core::f32::consts::FRAC_1_SQRT_2); let frac_2_pi = f16::from_f32(core::f32::consts::FRAC_2_PI); let frac_2_sqrt_pi = f16::from_f32(core::f32::consts::FRAC_2_SQRT_PI); let frac_pi_2 = f16::from_f32(core::f32::consts::FRAC_PI_2); let frac_pi_3 = f16::from_f32(core::f32::consts::FRAC_PI_3); let frac_pi_4 = f16::from_f32(core::f32::consts::FRAC_PI_4); let frac_pi_6 = f16::from_f32(core::f32::consts::FRAC_PI_6); let frac_pi_8 = f16::from_f32(core::f32::consts::FRAC_PI_8); let ln_10 = f16::from_f32(core::f32::consts::LN_10); let ln_2 = f16::from_f32(core::f32::consts::LN_2); let log10_e = f16::from_f32(core::f32::consts::LOG10_E); // core::f32::consts::LOG10_2 requires rustc 1.43.0 let log10_2 = f16::from_f32(2f32.log10()); let log2_e = f16::from_f32(core::f32::consts::LOG2_E); // core::f32::consts::LOG2_10 requires rustc 1.43.0 let log2_10 = f16::from_f32(10f32.log2()); let sqrt_2 = f16::from_f32(core::f32::consts::SQRT_2);
#[test] fn test_f16_consts_from_f64() { let one = f16::from_f64(1.0); let zero = f16::from_f64(0.0); let neg_zero = f16::from_f64(-0.0); let inf = f16::from_f64(core::f64::INFINITY); let neg_inf = f16::from_f64(core::f64::NEG_INFINITY); let nan = f16::from_f64(core::f64::NAN);
let e = f16::from_f64(core::f64::consts::E); let pi = f16::from_f64(core::f64::consts::PI); let frac_1_pi = f16::from_f64(core::f64::consts::FRAC_1_PI); let frac_1_sqrt_2 = f16::from_f64(core::f64::consts::FRAC_1_SQRT_2); let frac_2_pi = f16::from_f64(core::f64::consts::FRAC_2_PI); let frac_2_sqrt_pi = f16::from_f64(core::f64::consts::FRAC_2_SQRT_PI); let frac_pi_2 = f16::from_f64(core::f64::consts::FRAC_PI_2); let frac_pi_3 = f16::from_f64(core::f64::consts::FRAC_PI_3); let frac_pi_4 = f16::from_f64(core::f64::consts::FRAC_PI_4); let frac_pi_6 = f16::from_f64(core::f64::consts::FRAC_PI_6); let frac_pi_8 = f16::from_f64(core::f64::consts::FRAC_PI_8); let ln_10 = f16::from_f64(core::f64::consts::LN_10); let ln_2 = f16::from_f64(core::f64::consts::LN_2); let log10_e = f16::from_f64(core::f64::consts::LOG10_E); // core::f64::consts::LOG10_2 requires rustc 1.43.0 let log10_2 = f16::from_f64(2f64.log10()); let log2_e = f16::from_f64(core::f64::consts::LOG2_E); // core::f64::consts::LOG2_10 requires rustc 1.43.0 let log2_10 = f16::from_f64(10f64.log2()); let sqrt_2 = f16::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 = f16::from_f64(nan64); let neg_nan16_from_64 = f16::from_f64(neg_nan64); let nan16_from_32 = f16::from_f32(nan32); let neg_nan16_from_32 = f16::from_f32(neg_nan32);
#[test] fn test_nan_conversion_to_larger() { let nan16 = f16::from_bits(0x7C01u16); let neg_nan16 = f16::from_bits(0xFC01u16); 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_f16_to_f32() { let f = f16::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 = f16::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 * f16::EPSILON.to_f32());
#[test] fn test_f16_to_f64() { let f = f16::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 = f16::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 * f16::EPSILON.to_f64());
#[test] fn test_comparisons() { let zero = f16::from_f64(0.0); let one = f16::from_f64(1.0); let neg_zero = f16::from_f64(-0.0); let neg_one = f16::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.