Last active
April 4, 2023 18:57
-
-
Save shadeglare/db7352da608382248765a9245ec6ba7a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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