// Copyright (c) the JPEG XL Project Authors. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file.
//! IEEE 754 half-precision (binary16) floating-point type. //! //! This is a minimal implementation providing only the operations needed for JPEG XL decoding, //! avoiding external dependencies like `half` which pulls in `zerocopy`.
/// Creates an f16 from its raw bit representation. #[inline] pubconstfn from_bits(bits: u16) -> Self { Self(bits)
}
/// Returns the raw bit representation. #[inline] pubconstfn to_bits(self) -> u16 { self.0
}
/// Converts to f32. #[inline] pubfn to_f32(self) -> f32 { let bits = self.0; let sign = ((bits >> 15) & 1) as u32; let exp = ((bits >> 10) & 0x1F) as u32; let mant = (bits & 0x3FF) as u32;
let f32_bits = if exp == 0 { if mant == 0 { // Zero (signed)
sign << 31
} else { // Denormal f16 -> normalized f32 // Find the leading 1 bit in mantissa letmut m = mant; letmut e = 0u32; while (m & 0x400) == 0 {
m <<= 1;
e += 1;
}
m &= 0x3FF; // Remove the implicit leading 1 let new_exp = 127 - 15 - e; // Rebias: f16 bias=15, f32 bias=127
(sign << 31) | (new_exp << 23) | (m << 13)
}
} elseif exp == 31 { // Infinity or NaN if mant == 0 { // Infinity
(sign << 31) | (0xFF << 23)
} else { // NaN - preserve some payload bits, ensure quiet NaN
(sign << 31) | (0xFF << 23) | (mant << 13) | 0x0040_0000
}
} else { // Normal number // Rebias: f16 uses bias 15, f32 uses bias 127 // new_exp = exp - 15 + 127 = exp + 112 let new_exp = exp + 112;
(sign << 31) | (new_exp << 23) | (mant << 13)
};
f32::from_bits(f32_bits)
}
/// Creates an f16 from an f32. #[inline] pubfn from_f32(f: f32) -> Self { let bits = f.to_bits(); let sign = ((bits >> 31) & 1) as u16; let exp = ((bits >> 23) & 0xFF) as i32; let mant = bits & 0x007F_FFFF;
let h_bits = if exp == 0 { // Zero or f32 denormal -> f16 zero (too small)
sign << 15
} elseif exp == 255 { // Infinity or NaN if mant == 0 {
(sign << 15) | (0x1F << 10) // Infinity
} else {
(sign << 15) | (0x1F << 10) | 0x0200 // Quiet NaN
}
} else { let unbiased = exp - 127;
if unbiased < -24 { // Too small, underflow to zero
sign << 15
} elseif unbiased < -14 { // Denormal f16 let shift = (-14 - unbiased) as u32; let m = ((mant | 0x0080_0000) >> (shift + 14)) as u16;
(sign << 15) | m
} elseif unbiased > 15 { // Overflow to infinity
(sign << 15) | (0x1F << 10)
} else { // Normal f16 let h_exp = (unbiased + 15) as u16; let h_mant = (mant >> 13) as u16;
// Round to nearest, ties to even let round_bit = (mant >> 12) & 1; let sticky = mant & 0x0FFF; let h_mant = if round_bit == 1 && (sticky != 0 || (h_mant & 1) == 1) {
h_mant + 1
} else {
h_mant
};
/// Creates an f16 from an f64. #[inline] pubfn from_f64(f: f64) -> Self { // Convert via f32 - sufficient precision for f16 Self::from_f32(f as f32)
}
/// Converts to f64. #[inline] pubfn to_f64(self) -> f64 { self.to_f32() as f64
}
/// Returns true if this is neither infinite nor NaN. #[inline] pubfn is_finite(self) -> bool { // Exponent of 31 means infinity or NaN
((self.0 >> 10) & 0x1F) != 31
}
/// Returns the bytes in little-endian order. #[inline] pubconstfn to_le_bytes(self) -> [u8; 2] { self.0.to_le_bytes()
}
/// Returns the bytes in big-endian order. #[inline] pubconstfn to_be_bytes(self) -> [u8; 2] { self.0.to_be_bytes()
}
}
// NaN
assert!(f16::from_f32(f32::NAN).to_f32().is_nan());
}
#[test] fn test_overflow_to_infinity() { // f16 max is ~65504, values above should overflow to infinity let big = f16::from_f32(100000.0);
assert!(big.to_f32().is_infinite());
}
#[test] fn test_underflow_to_zero() { // Very small values should underflow to zero let tiny = f16::from_f32(1e-10);
assert_eq!(tiny.to_f32(), 0.0);
}
#[test] fn test_bytes() { let h = f16::from_bits(0x1234);
assert_eq!(h.to_le_bytes(), [0x34, 0x12]);
assert_eq!(h.to_be_bytes(), [0x12, 0x34]);
}
}
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.