blob: e5e5dfc7e895959ff1c859ddfc94317c0163404e [file] [edit]
// Copyright © 2026 Collabora, Ltd.
// SPDX-License-Identifier: MIT
use crate::bindings::*;
use std::cmp::{Ordering, PartialOrd};
use std::ops::Neg;
#[repr(transparent)]
#[derive(Clone, Copy, Default)]
pub struct F16 {
v: u16,
}
impl F16 {
pub const RADIX: u32 = 2;
pub const BITS: u32 = 16;
pub const MANTISSA_DIGITS: u32 = 11;
pub const EPSILON: F16 = F16::from_bits(0x1400);
pub const MIN: F16 = F16::from_bits(0xfbff);
pub const MIN_POSITIVE: F16 = F16::from_bits(0x0001);
pub const MAX: F16 = F16::from_bits(0x7bff);
pub const MIN_EXP: i32 = -14;
pub const MAX_EXP: i32 = 15;
pub const NAN: F16 = F16::from_bits(0x7e00);
pub const INFINITY: F16 = F16::from_bits(0x7c00);
pub const NEG_INFINITY: F16 = F16::from_bits(0xfc00);
const SIGN_BIT: u16 = 0x8000;
pub const fn abs(self) -> F16 {
F16::from_bits(self.to_bits() & !F16::SIGN_BIT)
}
pub fn from_f32_rtne(v: f32) -> F16 {
F16::from_bits(unsafe { _mesa_float_to_float16_rtne(v) })
}
pub fn from_f64_rtne(v: f64) -> F16 {
F16::from_bits(unsafe { _mesa_double_to_float16_rtne(v) })
}
pub const fn is_nan(self) -> bool {
self.abs().to_bits() > 0x7c00
}
pub const fn is_infinite(self) -> bool {
self.abs().to_bits() == F16::INFINITY.to_bits()
}
pub const fn is_finite(self) -> bool {
!self.is_infinite()
}
pub const fn is_sign_positive(self) -> bool {
(self.to_bits() & F16::SIGN_BIT) == 0
}
pub const fn is_sign_negative(self) -> bool {
!self.is_sign_positive()
}
pub const fn to_bits(self) -> u16 {
self.v
}
pub const fn from_bits(v: u16) -> F16 {
F16 { v }
}
pub fn max(self, other: F16) -> F16 {
if self.is_nan() {
self
} else if self < other {
other
} else {
// We also get here if other is nan
self
}
}
pub fn min(self, other: F16) -> F16 {
if self.is_nan() {
self
} else if self > other {
other
} else {
// We also get here if other is nan
self
}
}
}
impl From<F16> for f32 {
fn from(f: F16) -> f32 {
unsafe { _mesa_half_to_float(f.v) }
}
}
impl From<F16> for f64 {
fn from(f: F16) -> f64 {
unsafe { _mesa_half_to_float(f.v).into() }
}
}
impl PartialEq<F16> for F16 {
fn eq(&self, other: &F16) -> bool {
f32::from(*self).eq(&f32::from(*other))
}
}
impl PartialOrd<F16> for F16 {
fn partial_cmp(&self, other: &F16) -> Option<Ordering> {
f32::from(*self).partial_cmp(&f32::from(*other))
}
}
impl Neg for F16 {
type Output = F16;
fn neg(self) -> Self::Output {
F16 {
v: self.v ^ F16::SIGN_BIT,
}
}
}