move conversions into a file
This commit is contained in:
parent
2737974c8f
commit
9e23ce05a9
126
src/conv.rs
Normal file
126
src/conv.rs
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl From<u8> for F8 {
|
||||||
|
fn from(v: u8) -> Self {
|
||||||
|
if v == 0 {
|
||||||
|
return Self(0);
|
||||||
|
}
|
||||||
|
let e = v.ilog2() as u8;
|
||||||
|
let off = e as i8 - M_BITS as i8;
|
||||||
|
let m = if off >= 0 { v >> off } else { v << -off };
|
||||||
|
if e > E_MAX {
|
||||||
|
return Self(0xff);
|
||||||
|
}
|
||||||
|
Self::merge(m & M_STORAGE_MAX, e + E_BIAS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<F8> for u8 {
|
||||||
|
fn from(value: F8) -> Self {
|
||||||
|
if value.0 == 0 {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
let (m, e) = value.split_unbias();
|
||||||
|
match e {
|
||||||
|
0.. => m << e,
|
||||||
|
-7..0 => m >> -e,
|
||||||
|
..-7 => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<F8> for f32 {
|
||||||
|
fn from(value: F8) -> Self {
|
||||||
|
if value.0 == 0 {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
let (m, e) = value.split_unbias();
|
||||||
|
(m as f32) * (e as f32).exp2()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl F8 {
|
||||||
|
/// Split self into the mantissa and exponent, as stored.
|
||||||
|
pub(crate) fn split(self) -> (u8, u8) {
|
||||||
|
(self.0 & M_MASK, self.0 >> M_BITS)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Split self into integers (m, e) such that `self == m * 2.pow(e)`.
|
||||||
|
pub(crate) fn split_unbias(self) -> (u8, i8) {
|
||||||
|
let (m, e) = self.split();
|
||||||
|
(m | M_BIAS, e as i8 - (E_BIAS + M_BITS) as i8)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn merge(m: u8, e: u8) -> Self {
|
||||||
|
assert!(m <= M_STORAGE_MAX);
|
||||||
|
assert!(e <= E_STORAGE_MAX);
|
||||||
|
Self((e << M_BITS) | m)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn merge_unbias(in_m: u32, in_e: i32) -> Self {
|
||||||
|
if in_m == 0 {
|
||||||
|
return Self(0);
|
||||||
|
}
|
||||||
|
let base_e = in_m.ilog2() as u8;
|
||||||
|
let off = base_e as i8 - M_BITS as i8;
|
||||||
|
let m = if off >= 0 { in_m >> off } else { in_m << -off };
|
||||||
|
let e = (base_e as i32) + in_e + (E_BIAS as i32);
|
||||||
|
if e < 0 {
|
||||||
|
return Self(0);
|
||||||
|
}
|
||||||
|
if e > E_STORAGE_MAX as i32 {
|
||||||
|
return Self(0xff);
|
||||||
|
}
|
||||||
|
Self::merge(m as u8 & M_STORAGE_MAX, e as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_int_conv() {
|
||||||
|
assert_eq!(u8::from(F8(0)), 0);
|
||||||
|
assert_eq!(u8::from(F8::merge(0, 1)), 0);
|
||||||
|
assert_eq!(u8::from(F8::merge(0, E_BIAS - 1)), 0);
|
||||||
|
assert_eq!(u8::from(F8::merge(0, E_BIAS)), 1);
|
||||||
|
assert_eq!(u8::from(F8::merge(0, E_BIAS + 1)), 2);
|
||||||
|
assert_eq!(u8::from(F8::merge(0, E_STORAGE_MAX)), 1 << E_MAX);
|
||||||
|
for k in 0..=EXACT_INT_MAX {
|
||||||
|
assert_eq!(u8::from(F8::from(k)), k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_float_conv() {
|
||||||
|
assert_eq!(f32::from(F8(0)), 0.0);
|
||||||
|
assert_eq!(f32::from(F8::merge(0, E_BIAS)), 1.0);
|
||||||
|
assert_eq!(f32::from(F8::merge(0, E_BIAS - 1)), 0.5);
|
||||||
|
assert_eq!(f32::from(F8::merge(0, E_BIAS + 1)), 2.0);
|
||||||
|
assert_eq!(f32::from(F8::merge(1 << (M_BITS - 1), E_BIAS)), 1.5);
|
||||||
|
assert_eq!(f32::from(F8::merge(1 << (M_BITS - 1), E_BIAS - 1)), 0.75);
|
||||||
|
assert_eq!(
|
||||||
|
f32::from(F8::merge(0, E_STORAGE_MAX)),
|
||||||
|
(E_MAX as f32).exp2()
|
||||||
|
);
|
||||||
|
for k in 0..=EXACT_INT_MAX {
|
||||||
|
assert_eq!(f32::from(F8::from(k)), k as f32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_merge() {
|
||||||
|
assert_eq!(f32::from(F8::merge_unbias(0, 0)), 0.0);
|
||||||
|
assert_eq!(f32::from(F8::merge_unbias(1, 0)), 1.0);
|
||||||
|
assert_eq!(f32::from(F8::merge_unbias(1, 1)), 2.0);
|
||||||
|
assert_eq!(f32::from(F8::merge_unbias(1, -1)), 0.5);
|
||||||
|
assert_eq!(f32::from(F8::merge_unbias(3, 0)), 3.0);
|
||||||
|
assert_eq!(f32::from(F8::merge_unbias(3, 1)), 6.0);
|
||||||
|
assert_eq!(f32::from(F8::merge_unbias(3, -1)), 1.5);
|
||||||
|
assert_eq!(
|
||||||
|
f32::from(F8::merge_unbias(EXACT_INT_MAX.into(), 0)),
|
||||||
|
EXACT_INT_MAX as f32
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
121
src/lib.rs
121
src/lib.rs
|
|
@ -1,3 +1,4 @@
|
||||||
|
mod conv;
|
||||||
mod ops;
|
mod ops;
|
||||||
|
|
||||||
pub const M_BITS: u8 = 5;
|
pub const M_BITS: u8 = 5;
|
||||||
|
|
@ -23,42 +24,6 @@ const E_MASK: u8 = E_STORAGE_MAX << M_BITS;
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct F8(u8);
|
pub struct F8(u8);
|
||||||
|
|
||||||
impl F8 {
|
|
||||||
/// Split self into the mantissa and exponent, as stored.
|
|
||||||
fn split(self) -> (u8, u8) {
|
|
||||||
(self.0 & M_MASK, self.0 >> M_BITS)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Split self into integers (m, e) such that `self == m * 2.pow(e)`.
|
|
||||||
fn split_unbias(self) -> (u8, i8) {
|
|
||||||
let (m, e) = self.split();
|
|
||||||
(m | M_BIAS, e as i8 - (E_BIAS + M_BITS) as i8)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn merge(m: u8, e: u8) -> Self {
|
|
||||||
assert!(m <= M_STORAGE_MAX);
|
|
||||||
assert!(e <= E_STORAGE_MAX);
|
|
||||||
Self((e << M_BITS) | m)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn merge_unbias(in_m: u32, in_e: i32) -> Self {
|
|
||||||
if in_m == 0 {
|
|
||||||
return Self(0);
|
|
||||||
}
|
|
||||||
let base_e = in_m.ilog2() as u8;
|
|
||||||
let off = base_e as i8 - M_BITS as i8;
|
|
||||||
let m = if off >= 0 { in_m >> off } else { in_m << -off };
|
|
||||||
let e = (base_e as i32) + in_e + (E_BIAS as i32);
|
|
||||||
if e < 0 {
|
|
||||||
return Self(0);
|
|
||||||
}
|
|
||||||
if e > E_STORAGE_MAX as i32 {
|
|
||||||
return Self(0xff);
|
|
||||||
}
|
|
||||||
Self::merge(m as u8 & M_STORAGE_MAX, e as u8)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Binary for F8 {
|
impl std::fmt::Binary for F8 {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
if f.alternate() {
|
if f.alternate() {
|
||||||
|
|
@ -80,94 +45,10 @@ impl std::fmt::Debug for F8 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<u8> for F8 {
|
|
||||||
fn from(v: u8) -> Self {
|
|
||||||
if v == 0 {
|
|
||||||
return Self(0);
|
|
||||||
}
|
|
||||||
let e = v.ilog2() as u8;
|
|
||||||
let off = e as i8 - M_BITS as i8;
|
|
||||||
let m = if off >= 0 { v >> off } else { v << -off };
|
|
||||||
if e > E_MAX {
|
|
||||||
return Self(0xff);
|
|
||||||
}
|
|
||||||
Self::merge(m & M_STORAGE_MAX, e + E_BIAS)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<F8> for u8 {
|
|
||||||
fn from(value: F8) -> Self {
|
|
||||||
if value.0 == 0 {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
let (m, e) = value.split_unbias();
|
|
||||||
match e {
|
|
||||||
0.. => m << e,
|
|
||||||
-7..0 => m >> -e,
|
|
||||||
..-7 => 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<F8> for f32 {
|
|
||||||
fn from(value: F8) -> Self {
|
|
||||||
if value.0 == 0 {
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
let (m, e) = value.split_unbias();
|
|
||||||
(m as f32) * (e as f32).exp2()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_int_conv() {
|
|
||||||
assert_eq!(u8::from(F8(0)), 0);
|
|
||||||
assert_eq!(u8::from(F8::merge(0, 1)), 0);
|
|
||||||
assert_eq!(u8::from(F8::merge(0, E_BIAS - 1)), 0);
|
|
||||||
assert_eq!(u8::from(F8::merge(0, E_BIAS)), 1);
|
|
||||||
assert_eq!(u8::from(F8::merge(0, E_BIAS + 1)), 2);
|
|
||||||
assert_eq!(u8::from(F8::merge(0, E_STORAGE_MAX)), 1 << E_MAX);
|
|
||||||
for k in 0..=EXACT_INT_MAX {
|
|
||||||
assert_eq!(u8::from(F8::from(k)), k);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_float_conv() {
|
|
||||||
assert_eq!(f32::from(F8(0)), 0.0);
|
|
||||||
assert_eq!(f32::from(F8::merge(0, E_BIAS)), 1.0);
|
|
||||||
assert_eq!(f32::from(F8::merge(0, E_BIAS - 1)), 0.5);
|
|
||||||
assert_eq!(f32::from(F8::merge(0, E_BIAS + 1)), 2.0);
|
|
||||||
assert_eq!(f32::from(F8::merge(1 << (M_BITS - 1), E_BIAS)), 1.5);
|
|
||||||
assert_eq!(f32::from(F8::merge(1 << (M_BITS - 1), E_BIAS - 1)), 0.75);
|
|
||||||
assert_eq!(
|
|
||||||
f32::from(F8::merge(0, E_STORAGE_MAX)),
|
|
||||||
(E_MAX as f32).exp2()
|
|
||||||
);
|
|
||||||
for k in 0..=EXACT_INT_MAX {
|
|
||||||
assert_eq!(f32::from(F8::from(k)), k as f32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_merge() {
|
|
||||||
assert_eq!(f32::from(F8::merge_unbias(0, 0)), 0.0);
|
|
||||||
assert_eq!(f32::from(F8::merge_unbias(1, 0)), 1.0);
|
|
||||||
assert_eq!(f32::from(F8::merge_unbias(1, 1)), 2.0);
|
|
||||||
assert_eq!(f32::from(F8::merge_unbias(1, -1)), 0.5);
|
|
||||||
assert_eq!(f32::from(F8::merge_unbias(3, 0)), 3.0);
|
|
||||||
assert_eq!(f32::from(F8::merge_unbias(3, 1)), 6.0);
|
|
||||||
assert_eq!(f32::from(F8::merge_unbias(3, -1)), 1.5);
|
|
||||||
assert_eq!(
|
|
||||||
f32::from(F8::merge_unbias(EXACT_INT_MAX.into(), 0)),
|
|
||||||
EXACT_INT_MAX as f32
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_display() {
|
fn test_display() {
|
||||||
fn fmt_split(m: u8, e: u8) -> String {
|
fn fmt_split(m: u8, e: u8) -> String {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user