use crate::{digit::*, Index, Cutoff, cutoff::*, BigFixed, BigFixedError};
use std::{convert::{From}, cmp::{max}};
impl BigFixed {
pub fn int_from_bytes(bytes: &[u8], unsigned: bool) -> Result<BigFixed, BigFixedError> {
let good_len = bytes.len() / DIGITBYTES;
let good_bytes_len = good_len * DIGITBYTES;
let mut data: Vec<Digit> = Vec::with_capacity(good_len + 1);
data.extend(
(0..good_len).map(
|i| i * DIGITBYTES
).map(
|j| digit_from_bytes(
&bytes[j..(j+DIGITBYTES)]
)
)
);
if bytes.len() != good_bytes_len {
let fill: u8 = if !unsigned && bytes[bytes.len()-1] >= 128 {255} else {0};
let mut int_bytes = [fill; DIGITBYTES];
let fill_len = bytes.len() - good_bytes_len;
int_bytes[0..fill_len].clone_from_slice(&bytes[good_bytes_len..bytes.len()]);
data.push(digit_from_bytes(&int_bytes));
}
let is_neg = !unsigned && data.len() > 0 && data[data.len()-1] >= GREATESTBIT;
BigFixed::construct(
if is_neg {ALLONES} else {0},
data,
Index::Position(0)
)
}
pub fn float_from_bits(mut self, exponent_len: usize, exponent_bias: isize, significand_len: usize) -> Result<BigFixed, BigFixedError> {
assert!(!self.is_neg() && self.position >= 0isize, "improper float format");
self = self.shift(Index::Bit(-Index::castsize(exponent_len + significand_len)?))?;
let is_neg = self[0] == 1;
self[0] = 0;
self = self.shift(Index::Bit(Index::castsize(exponent_len)?))?;
let exp = Index::castsize(<usize>::from(&self))? - exponent_bias;
for i in 0..max(0, self.body_high()?.value()) {
self[i] = 0;
}
if self.is_zero() && exp == exponent_bias {
self.format()?;
return Ok(self);
}
self[0] = 1;
self = self.shift(Index::Bit(exp))?;
if is_neg {
self.negate()?;
}
Ok(self)
}
pub fn float_to_bits(mut self, exponent_len: usize, exponent_bias: isize, significand_len: usize) -> Result<BigFixed, BigFixedError> {
if self.is_zero() {
return Ok(self);
}
let neg = self.is_neg();
if neg {
self.negate()?;
};
let position = self.greatest_bit_position()?;
self = self.shift((-position)?)?;
self.body.pop();
let low_pos = (-Index::Bit(Index::castsize(significand_len + DIGITBITS - 1)?))?;
self.cutoff(Cutoff{
fixed: Some(low_pos),
floating: None,
round: Rounding::Floor
})?;
if self.body.len() > 0 {
self[low_pos] &= ALLONES << (DIGITBITS - (significand_len % DIGITBITS));
}
let mut exp = (position + exponent_bias)?.value();
let max_exp = Index::castsize((ALLONES >> (DIGITBITS - exponent_len)) as usize)?;
if exp < 0 {
exp = 0;
self.clear();
} else if exp > max_exp {
exp = max_exp;
self.clear();
}
self |= &BigFixed::from(exp);
self = self.shift((-Index::Bit(Index::castsize(exponent_len)?))?)?;
if neg {
self |= &BigFixed::from(1);
}
self = self.shift((Index::Bit(Index::castsize(exponent_len)?) + Index::Bit(Index::castsize(significand_len)?))?)?;
Ok(self)
}
}
impl From<&[u8]> for BigFixed {
fn from(bytes: &[u8]) -> BigFixed {
BigFixed::int_from_bytes(bytes, true).unwrap()
}
}
impl From<&[i8]> for BigFixed {
fn from(bytes: &[i8]) -> BigFixed {
let bytes: Vec<u8> = bytes.iter().map(|b| *b as u8).collect();
BigFixed::int_from_bytes(bytes.as_slice(), false).unwrap()
}
}
macro_rules! from_signed_int {
($s: ty, $n: expr) => {
impl From<$s> for BigFixed {
fn from(i: $s) -> BigFixed {
BigFixed::int_from_bytes(&i.to_le_bytes() as &[u8], false).unwrap()
}
}
};
}
macro_rules! from_unsigned_int {
($u: ty, $num_bytes: expr) => {
impl From<$u> for BigFixed {
fn from(u: $u) -> BigFixed {
BigFixed::int_from_bytes(&u.to_le_bytes() as &[u8], true).unwrap()
}
}
};
}
const SIZEBYTES: usize = (usize::BITS / 8) as usize;
from_signed_int!(isize, SIZEBYTES);
from_unsigned_int!(usize, SIZEBYTES);
from_signed_int!(i8, 1);
from_unsigned_int!(u8, 1);
from_signed_int!(i16, 2);
from_unsigned_int!(u16, 2);
from_signed_int!(i32, 4);
from_unsigned_int!(u32, 4);
from_signed_int!(i64, 8);
from_unsigned_int!(u64, 8);
from_signed_int!(i128, 16);
from_unsigned_int!(u128, 16);
macro_rules! to_unsigned_int {
($int: ty, $num_bytes: expr) => {
impl From<&BigFixed> for $int {
fn from(x: &BigFixed) -> $int {
if DIGITBYTES >= $num_bytes {
let mut bytes = [0u8; $num_bytes];
let d = x[0].to_le_bytes();
bytes[0..$num_bytes].copy_from_slice(&d[0..$num_bytes]);
<$int>::from_le_bytes(bytes)
} else {
assert_eq!($num_bytes % DIGITBYTES, 0, "byte number mismatch");
let len = $num_bytes / DIGITBYTES;
let mut bytes = [0u8; $num_bytes];
let mut on = 0;
for i in 0..len {
let d = x[i as isize].to_le_bytes();
for j in 0..DIGITBYTES {
bytes[on] = d[j];
on += 1;
}
}
<$int>::from_le_bytes(bytes)
}
}
}
};
}
to_unsigned_int!(usize, SIZEBYTES);
to_unsigned_int!(u8, 1);
to_unsigned_int!(u16, 2);
to_unsigned_int!(u32, 4);
to_unsigned_int!(u64, 8);
to_unsigned_int!(u128, 16);
macro_rules! to_signed_int {
($int: ty, $unsigned: ty, $num_bytes: expr) => {
impl From<&BigFixed> for $int {
fn from(x: &BigFixed) -> $int {
let cutoff: $unsigned = 1 as $unsigned << (8 * $num_bytes - 1);
let mut c = BigFixed::from(cutoff);
if x >= &c {
(cutoff - 1) as $int
} else {
c.negate().unwrap();
if x < &c {
cutoff as $int
} else {
<$unsigned>::from(x) as $int
}
}
}
}
};
}
to_signed_int!(isize, usize, SIZEBYTES);
to_signed_int!(i8, u8, 1);
to_signed_int!(i16, u16, 2);
to_signed_int!(i32, u32, 4);
to_signed_int!(i64, u64, 8);
to_signed_int!(i128, u128, 16);
macro_rules! from_float {
($type: ty, $exponent_len: expr, $exponent_bias: expr, $significand_len: expr) => {
impl From<$type> for BigFixed {
fn from(x: $type) -> BigFixed {
let mut returner = BigFixed::from(x.to_bits());
returner = returner.float_from_bits($exponent_len, $exponent_bias, $significand_len).unwrap();
returner
}
}
};
}
from_float!(f32, 8, 127, 23);
from_float!(f64, 11, 1023, 52);
macro_rules! to_float {
($type: ty, $unsigned_type: ty, $exponent_len: expr, $exponent_bias: expr, $significand_len: expr) => {
impl From<BigFixed> for $type {
fn from(mut x: BigFixed) -> $type {
x = x.float_to_bits($exponent_len, $exponent_bias, $significand_len).unwrap();
<$type>::from_bits(
<$unsigned_type>::from(&x)
)
}
}
}
}
to_float!(f32, u32, 8, 127, 23);
to_float!(f64, u64, 11, 1023, 52);