4 traits::{ConvertFrom, ConvertTo, Float},
8 ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign},
11 #[cfg(feature = "f16")]
12 use half::f16 as F16Impl;
14 #[cfg(not(feature = "f16"))]
17 #[derive(Clone, Copy, PartialEq, PartialOrd)]
19 pub struct F16(F16Impl);
21 #[cfg(not(feature = "f16"))]
23 pub(crate) fn panic_f16_feature_disabled() -> ! {
24 panic!("f16 feature is not enabled")
27 #[cfg(feature = "f16")]
28 macro_rules! f16_impl {
29 ($v:expr, [$($vars:ident),*]) => {
34 #[cfg(not(feature = "f16"))]
35 macro_rules! f16_impl {
36 ($v:expr, [$($vars:ident),*]) => {
39 panic_f16_feature_disabled()
44 impl fmt::Display for F16 {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 f16_impl!(self.0.fmt(f), [f])
50 impl fmt::LowerExp for F16 {
51 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52 f16_impl!(self.0.fmt(f), [f])
56 impl fmt::UpperExp for F16 {
57 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58 f16_impl!(self.0.fmt(f), [f])
62 impl fmt::Debug for F16 {
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 f16_impl!(self.0.fmt(f), [f])
68 impl Default for F16 {
69 fn default() -> Self {
70 f16_impl!(F16(F16Impl::default()), [])
74 impl From<F16Impl> for F16 {
75 fn from(v: F16Impl) -> Self {
80 impl From<F16> for F16Impl {
81 fn from(v: F16) -> Self {
86 macro_rules! impl_f16_from {
89 impl From<$ty> for F16 {
90 fn from(v: $ty) -> Self {
91 f16_impl!(F16(F16Impl::from(v)), [v])
95 impl ConvertFrom<$ty> for F16 {
96 fn cvt_from(v: $ty) -> F16 {
104 macro_rules! impl_from_f16 {
105 ($($ty:ident,)*) => {
107 impl From<F16> for $ty {
108 fn from(v: F16) -> Self {
109 f16_impl!(v.0.into(), [v])
113 impl ConvertFrom<F16> for $ty {
114 fn cvt_from(v: F16) -> Self {
122 impl_f16_from![i8, u8,];
124 impl_from_f16![f32, f64,];
126 macro_rules! impl_int_to_f16 {
127 ($($int:ident),*) => {
129 impl ConvertFrom<$int> for F16 {
130 fn cvt_from(v: $int) -> Self {
131 // f32 has enough mantissa bits such that f16 overflows to
132 // infinity before f32 stops being able to properly
133 // represent integer values, making the below conversion correct.
134 F16::cvt_from(v as f32)
141 macro_rules! impl_f16_to_int {
142 ($($int:ident),*) => {
144 impl ConvertFrom<F16> for $int {
145 fn cvt_from(v: F16) -> Self {
153 impl_int_to_f16![i16, u16, i32, u32, i64, u64, i128, u128];
154 impl_f16_to_int![i8, u8, i16, u16, i32, u32, i64, u64, i128, u128];
156 impl ConvertFrom<f32> for F16 {
157 fn cvt_from(v: f32) -> Self {
158 f16_impl!(F16(F16Impl::from_f32(v)), [v])
162 impl ConvertFrom<f64> for F16 {
163 fn cvt_from(v: f64) -> Self {
164 f16_impl!(F16(F16Impl::from_f64(v)), [v])
171 fn neg(self) -> Self::Output {
172 f16_impl!(Self::from_bits(self.to_bits() ^ 0x8000), [])
176 macro_rules! impl_bin_op_using_f32 {
177 ($($op:ident, $op_fn:ident, $op_assign:ident, $op_assign_fn:ident;)*) => {
182 fn $op_fn(self, rhs: Self) -> Self::Output {
183 f32::from(self).$op_fn(f32::from(rhs)).to()
187 impl $op_assign for F16 {
188 fn $op_assign_fn(&mut self, rhs: Self) {
189 *self = (*self).$op_fn(rhs);
196 impl_bin_op_using_f32! {
197 Add, add, AddAssign, add_assign;
198 Sub, sub, SubAssign, sub_assign;
199 Mul, mul, MulAssign, mul_assign;
200 Div, div, DivAssign, div_assign;
201 Rem, rem, RemAssign, rem_assign;
205 pub fn from_bits(v: u16) -> Self {
206 #[cfg(feature = "f16")]
207 return F16(F16Impl::from_bits(v));
208 #[cfg(not(feature = "f16"))]
211 pub fn to_bits(self) -> u16 {
212 #[cfg(feature = "f16")]
213 return self.0.to_bits();
214 #[cfg(not(feature = "f16"))]
217 pub fn abs(self) -> Self {
218 f16_impl!(Self::from_bits(self.to_bits() & 0x7FFF), [])
220 pub fn copysign(self, sign: Self) -> Self {
222 Self::from_bits((self.to_bits() & 0x7FFF) | (sign.to_bits() & 0x8000)),
226 pub fn trunc(self) -> Self {
227 return PrimFloat::trunc(f32::from(self)).to();
229 pub fn ceil(self) -> Self {
230 return PrimFloat::ceil(f32::from(self)).to();
232 pub fn floor(self) -> Self {
233 return PrimFloat::floor(f32::from(self)).to();
235 /// round to nearest, ties to unspecified
236 pub fn round(self) -> Self {
237 return PrimFloat::round(f32::from(self)).to();
239 #[cfg(feature = "fma")]
240 pub fn fma(self, a: Self, b: Self) -> Self {
241 (f64::from(self) * f64::from(a) + f64::from(b)).to()
244 pub fn is_nan(self) -> bool {
245 f16_impl!(self.0.is_nan(), [])
248 pub fn is_infinite(self) -> bool {
249 f16_impl!(self.0.is_infinite(), [])
252 pub fn is_finite(self) -> bool {
253 f16_impl!(self.0.is_finite(), [])
257 impl Float for Value<F16> {
258 type PrimFloat = F16;
259 type BitsType = Value<u16>;
260 type SignedBitsType = Value<i16>;
262 fn abs(self) -> Self {
266 fn trunc(self) -> Self {
267 Value(self.0.trunc())
270 fn ceil(self) -> Self {
274 fn floor(self) -> Self {
275 Value(self.0.floor())
278 fn round(self) -> Self {
279 Value(self.0.round())
282 #[cfg(feature = "fma")]
283 fn fma(self, a: Self, b: Self) -> Self {
284 Value(self.0.fma(a.0, b.0))
287 fn is_nan(self) -> Self::Bool {
288 Value(self.0.is_nan())
291 fn is_infinite(self) -> Self::Bool {
292 Value(self.0.is_infinite())
295 fn is_finite(self) -> Self::Bool {
296 Value(self.0.is_finite())
299 fn from_bits(v: Self::BitsType) -> Self {
300 Value(F16::from_bits(v.0))
303 fn to_bits(self) -> Self::BitsType {
304 Value(self.0.to_bits())
311 use core::cmp::Ordering;
315 not(feature = "f16"),
316 should_panic(expected = "f16 feature is not enabled")
319 assert_eq!(F16::from_bits(0x8000).abs().to_bits(), 0);
320 assert_eq!(F16::from_bits(0).abs().to_bits(), 0);
321 assert_eq!(F16::from_bits(0x8ABC).abs().to_bits(), 0xABC);
322 assert_eq!(F16::from_bits(0xFE00).abs().to_bits(), 0x7E00);
323 assert_eq!(F16::from_bits(0x7E00).abs().to_bits(), 0x7E00);
328 not(feature = "f16"),
329 should_panic(expected = "f16 feature is not enabled")
332 assert_eq!(F16::from_bits(0x8000).neg().to_bits(), 0);
333 assert_eq!(F16::from_bits(0).neg().to_bits(), 0x8000);
334 assert_eq!(F16::from_bits(0x8ABC).neg().to_bits(), 0xABC);
335 assert_eq!(F16::from_bits(0xFE00).neg().to_bits(), 0x7E00);
336 assert_eq!(F16::from_bits(0x7E00).neg().to_bits(), 0xFE00);
341 not(feature = "f16"),
342 should_panic(expected = "f16 feature is not enabled")
344 fn test_int_to_f16() {
345 assert_eq!(F16::to_bits(0u32.to()), 0);
346 for v in 1..0x20000u32 {
347 let leading_zeros = u32::leading_zeros(v);
348 let shifted_v = v << leading_zeros;
349 // round to nearest, ties to even
350 let round_up = match (shifted_v & 0x1FFFFF).cmp(&0x100000) {
351 Ordering::Less => false,
352 Ordering::Equal => (shifted_v & 0x200000) != 0,
353 Ordering::Greater => true,
355 let (rounded, carry) =
356 (shifted_v & !0x1FFFFF).overflowing_add(round_up.then(|| 0x200000).unwrap_or(0));
359 mantissa = (rounded >> 22) as u16 + 0x400;
361 mantissa = (rounded >> 21) as u16;
363 assert_eq!((mantissa & !0x3FF), 0x400);
364 let exponent = 31 - leading_zeros as u16 + 15 + carry as u16;
365 let expected = if exponent < 0x1F {
366 (mantissa & 0x3FF) + (exponent << 10)
370 let actual = F16::to_bits(v.to());
373 "actual = {:#X}, expected = {:#X}, v = {:#X}",