simplify fraction to string

This commit is contained in:
Trevor Spiteri 2019-08-08 14:48:46 +02:00
parent e0a4f2a606
commit b9e92b5d95
1 changed files with 78 additions and 9 deletions

View File

@ -22,7 +22,7 @@ use crate::{
use core::{ use core::{
cmp::Ordering, cmp::Ordering,
fmt::{Binary, Debug, Display, Formatter, LowerHex, Octal, Result as FmtResult, UpperHex}, fmt::{Binary, Debug, Display, Formatter, LowerHex, Octal, Result as FmtResult, UpperHex},
str, mem, str,
}; };
trait Radix2 { trait Radix2 {
@ -238,8 +238,36 @@ fn dec_frac_digits(frac_bits: u32) -> u32 {
(frac_bits * 3 + i) / 10 (frac_bits * 3 + i) / 10
} }
trait Mul10: Sized {
fn mul10(self) -> (Self, u8);
}
macro_rules! mul10_widen {
($Single:ty, $Double:ty) => {
impl Mul10 for $Single {
#[inline]
fn mul10(self) -> ($Single, u8) {
const NBITS: usize = 8 * mem::size_of::<$Single>();
let prod = <$Double>::from(self) * 10;
(prod as $Single, (prod >> NBITS) as u8)
}
}
};
}
mul10_widen! { u8, u16 }
mul10_widen! { u16, u32 }
mul10_widen! { u32, u64 }
mul10_widen! { u64, u128 }
impl Mul10 for u128 {
#[inline]
fn mul10(self) -> (u128, u8) {
const LO_MASK: u128 = !(!0 << 64);
let hi = (self >> 64) * 10;
let lo = (self & LO_MASK) * 10;
((hi << 64) + lo, (hi >> 64) as u8)
}
}
trait FmtDecHelper: SealedInt { trait FmtDecHelper: SealedInt {
fn cmp_half(&self) -> Ordering;
fn take_int_digit(&mut self) -> u8; fn take_int_digit(&mut self) -> u8;
fn take_frac_digit(&mut self) -> u8; fn take_frac_digit(&mut self) -> u8;
} }
@ -247,11 +275,6 @@ trait FmtDecHelper: SealedInt {
macro_rules! fmt_dec_helper { macro_rules! fmt_dec_helper {
($($UInner:ty)*) => { $( ($($UInner:ty)*) => { $(
impl FmtDecHelper for $UInner { impl FmtDecHelper for $UInner {
#[inline]
fn cmp_half(&self) -> Ordering {
self.cmp(&<$UInner>::MSB)
}
#[inline] #[inline]
fn take_int_digit(&mut self) -> u8 { fn take_int_digit(&mut self) -> u8 {
let ret = (*self % 10) as u8; let ret = (*self % 10) as u8;
@ -261,8 +284,7 @@ macro_rules! fmt_dec_helper {
#[inline] #[inline]
fn take_frac_digit(&mut self) -> u8 { fn take_frac_digit(&mut self) -> u8 {
let next = self.wrapping_mul(10); let (next, ret) = self.mul10();
let ret = ((*self - next / 10) / (!0 / 10)) as u8;
*self = next; *self = next;
ret ret
} }
@ -462,6 +484,53 @@ mod tests {
} }
} }
#[test]
fn all_frac() {
use crate::types::{I0F128, I0F16, I0F32, I0F64, I0F8, U0F128, U0F16, U0F32, U0F64, U0F8};
assert_eq_fmt!(
("{:X}", I0F128::from_bits(!0)),
("{}", "-0.00000000000000000000000000000001")
);
assert_eq_fmt!(
("{:X}", I0F64::from_bits(!0)),
("{}", "-0.0000000000000001")
);
assert_eq_fmt!(("{:X}", I0F32::from_bits(!0)), ("{}", "-0.00000001"));
assert_eq_fmt!(("{:X}", I0F16::from_bits(!0)), ("{}", "-0.0001"));
assert_eq_fmt!(("{:X}", I0F8::from_bits(!0)), ("{}", "-0.01"));
assert_eq_fmt!(
("{:X}", U0F128::from_bits(!0)),
("{}", "0.FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
);
assert_eq_fmt!(("{:X}", U0F64::from_bits(!0)), ("{}", "0.FFFFFFFFFFFFFFFF"));
assert_eq_fmt!(("{:X}", U0F32::from_bits(!0)), ("{}", "0.FFFFFFFF"));
assert_eq_fmt!(("{:X}", U0F16::from_bits(!0)), ("{}", "0.FFFF"));
assert_eq_fmt!(("{:X}", U0F8::from_bits(!0)), ("{}", "0.FF"));
assert_eq_fmt!(
("{}", I0F128::from_bits(!0)),
("{}", "-0.000000000000000000000000000000000000003")
);
assert_eq_fmt!(
("{}", I0F64::from_bits(!0)),
("{}", "-0.00000000000000000005")
);
assert_eq_fmt!(("{}", I0F32::from_bits(!0)), ("{}", "-0.0000000002"));
assert_eq_fmt!(("{}", I0F16::from_bits(!0)), ("{}", "-0.00002"));
assert_eq_fmt!(("{}", I0F8::from_bits(!0)), ("{}", "-0.004"));
assert_eq_fmt!(
("{}", U0F128::from_bits(!0)),
("{}", "0.999999999999999999999999999999999999997")
);
assert_eq_fmt!(
("{}", U0F64::from_bits(!0)),
("{}", "0.99999999999999999995")
);
assert_eq_fmt!(("{}", U0F32::from_bits(!0)), ("{}", "0.9999999998"));
assert_eq_fmt!(("{}", U0F16::from_bits(!0)), ("{}", "0.99998"));
assert_eq_fmt!(("{}", U0F8::from_bits(!0)), ("{}", "0.996"));
}
fn pow(base: u32, mut exp: u32) -> f64 { fn pow(base: u32, mut exp: u32) -> f64 {
let mut mult = f64::from(base); let mut mult = f64::from(base);
let mut result = 1.0; let mut result = 1.0;