Skip to content

Instantly share code, notes, and snippets.

@shadeglare
Last active April 4, 2023 18:57
Show Gist options
  • Save shadeglare/db7352da608382248765a9245ec6ba7a to your computer and use it in GitHub Desktop.
Save shadeglare/db7352da608382248765a9245ec6ba7a to your computer and use it in GitHub Desktop.
use std::ops::Deref;
pub trait FloatBitOps {
type UBits;
type SBits;
fn sign_bit_left(self) -> Self::UBits;
fn exponent_bits_left(self) -> Self::UBits;
fn mantissa_bits_left(self) -> Self::UBits;
fn sign_bit_right(self) -> Self::UBits;
fn exponent_bits_right(self) -> Self::UBits;
fn mantissa_bits_right(self) -> Self::UBits;
fn exponent_value(self) -> Self::SBits;
fn decimal_bits_left(self) -> Self::UBits;
fn decimal_bits_right(self) -> Self::UBits;
}
macro_rules! impl_float_bit_ops {
($type:ty, $ubits:ty, $sbits:ty, $sign_bit_count:literal, $exponent_bit_count:literal, $mantissa_bit_count:literal, $sign_mask:literal, $mantissa_mask:literal, $exp_bias:literal) => {
impl FloatBitOps for $type {
type UBits = $ubits;
type SBits = $sbits;
#[inline(always)]
fn sign_bit_left(self) -> Self::UBits {
*self & $sign_mask
}
#[inline(always)]
fn exponent_bits_left(self) -> Self::UBits {
*self >> $mantissa_bit_count << $sign_bit_count << $mantissa_bit_count
}
#[inline(always)]
fn mantissa_bits_left(self) -> Self::UBits {
*self << $sign_bit_count << $exponent_bit_count
}
#[inline(always)]
fn sign_bit_right(self) -> Self::UBits {
*self >> $exponent_bit_count >> $mantissa_bit_count
}
#[inline(always)]
fn exponent_bits_right(self) -> Self::UBits {
*self << $sign_bit_count >> $sign_bit_count >> $mantissa_bit_count
}
#[inline(always)]
fn mantissa_bits_right(self) -> Self::UBits {
*self & $mantissa_mask
}
#[inline(always)]
fn exponent_value(self) -> Self::SBits {
self.exponent_bits_right() as Self::SBits - $exp_bias
}
#[inline(always)]
fn decimal_bits_left(self) -> Self::UBits {
let value = self.exponent_value();
if value < 0 {
self.mantissa_bits_left() >> value.abs()
} else {
self.mantissa_bits_left() << value
}
}
#[inline(always)]
fn decimal_bits_right(self) -> Self::UBits {
let value = self.exponent_value();
let mask = if value < 0 {
!(Self::UBits::MAX << $mantissa_bit_count >> value.abs())
} else {
!(Self::UBits::MAX << $mantissa_bit_count << value)
};
self.mantissa_bits_right() & mask
}
}
};
}
pub trait ToFloatBits {
type Target;
fn to_float_bits(self) -> Self::Target;
}
#[repr(transparent)]
#[derive(Clone, Copy, Debug)]
pub struct SingleFloatBits(u32);
impl SingleFloatBits {
#[inline(always)]
pub fn new(value: f32) -> Self {
Self(value.to_bits())
}
}
impl Deref for SingleFloatBits {
type Target = u32;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<f32> for SingleFloatBits {
#[inline(always)]
fn from(value: f32) -> Self {
Self::new(value)
}
}
impl_float_bit_ops!(
SingleFloatBits,
u32,
i32,
0x1,
0x8,
0x17,
0x8000_0000_u32,
0x003f_ffff_u32,
0x7f
);
impl ToFloatBits for f32 {
type Target = SingleFloatBits;
#[inline(always)]
fn to_float_bits(self) -> Self::Target {
Self::Target::new(self)
}
}
#[repr(transparent)]
#[derive(Clone, Copy, Debug)]
pub struct DoubleFloatBits(u64);
impl DoubleFloatBits {
#[inline(always)]
pub fn new(value: f64) -> Self {
Self(value.to_bits())
}
}
impl Deref for DoubleFloatBits {
type Target = u64;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<f64> for DoubleFloatBits {
#[inline(always)]
fn from(value: f64) -> Self {
Self::new(value)
}
}
impl_float_bit_ops!(
DoubleFloatBits,
u64,
i64,
0x1,
0xb,
0x34,
0x8000_0000_0000_0000_u64,
0x000f_ffff_ffff_ffff_u64,
0x3ff
);
impl ToFloatBits for f64 {
type Target = DoubleFloatBits;
#[inline(always)]
fn to_float_bits(self) -> Self::Target {
Self::Target::new(self)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment