unums 0.0.1

A crate for using Unums
Documentation

use super::utils::ToUnumHelpers;
use super::env;
use std::marker::PhantomData;


#[derive(Debug)]
struct Unum<E> where E: env::UnumEnv {
    env: PhantomData<E>,
    sign: bool,
    exp_bits: u32,
    frac_bits: u32,
    ubit: bool,
    exp_size: u8,
    frac_size: u8,
}


impl<E> Unum<E> where E: env::UnumEnv {

    fn nan() -> Unum<E> { Unum::zero() } // TODO: fix this
    fn infinity() -> Unum<E>  { Unum::zero() } //TODO: fix this
    
    fn zero() -> Unum<E> {
        Unum{
            env: PhantomData,
            sign: true,
            exp_bits: 0x00000000,
            frac_bits: 0x00000000,
            ubit: false,
            exp_size: 0,
            frac_size: 0,
        }
    }
    
    fn from_i32_old(n: i32) -> Unum<E> {
        match n {
            0 => Unum::zero(),
            _ => {
                let mut counter = 0;
                let n_f64 : f64 = n.into();
                let mut y : f64 = n_f64.abs() / (2_f64).powi(n.floor_log_2_abs() as i32);

                println!("floor_log_2_abs_i32(n) = {}", n.floor_log_2_abs());
                println!("(2_f64).powi(floor_log_2_abs_i32(n)) = {}", (2_f64).powi(n.floor_log_2_abs() as i32));
                println!("pre y = {}", y);
                println!("pre y.floor() = {}", y.floor());
                while y.floor() != y && counter < (E::f_size_size() as i32) {
                    counter += 1;
                    y *= 2_f64;
                }
                println!("final y = {}", y);
                println!("final y.floor() = {}", y.floor());
                // we have an exact value, aka an integer
                if y == y.floor() {
                    let y_int : i64 = y as i64;
                    return Unum {
                        env: PhantomData,
                        sign: n >= 0,
                        exp_bits: ((n.floor_log_2_abs() as i32) + 2_i32.pow((n.min_exp_bits() as u32) - 1) -1) as u32,
                        frac_bits: if counter == 0 {0} else {(y_int - 2_i64.pow(y_int.floor_log_2_abs() as u32)) as u32},
                        ubit: false,
                        exp_size: (n.min_exp_bits() - 1) as u8,
                        frac_size: (counter - if counter>0 {1} else {0}) as u8,
                    }
                } else {
                    panic!("Failed to find floor of int equal to int.")
                }
            }
        }
    }

}

macro_rules! FromIntForUnum {
    ($T:ty) => {
        impl<E> From<$T> for Unum<E> where E: env::UnumEnv {
            #[allow(unused_comparisons)]
            fn from(n: $T) -> Unum<E> { 
                match n {
                    0 => Unum::zero(),
                    _ => {
                        let counter = n.floor_log_2_abs() as i32;
                        let y_int : i64 = n.abs_val() as i64;
                        Unum {
                            env: PhantomData,
                            sign: n >= 0,
                            exp_bits: (counter + 2_i32.pow((n.min_exp_bits() as u32) - 1) -1) as u32,
                            frac_bits: if counter == 0 {0} else {(y_int - 2_i64.pow(counter as u32)) as u32},
                            ubit: false,
                            exp_size: (n.min_exp_bits() - 1) as u8,
                            frac_size: (counter - if counter>0 {1} else {0}) as u8,
                        }
                    }
                }
            }
        }
    }
}

FromIntForUnum!(usize);
FromIntForUnum!(u8);
FromIntForUnum!(u16);
FromIntForUnum!(u32);
FromIntForUnum!(u64);

FromIntForUnum!(isize);
FromIntForUnum!(i8);
FromIntForUnum!(i16);
FromIntForUnum!(i32);
FromIntForUnum!(i64);


macro_rules! FromFloatForUnum {
    ($T:ty) => {
        impl<E> From<$T> for Unum<E> where E: env::UnumEnv {
            #[allow(unused_comparisons)]
            fn from(n: $T) -> Unum<E> { 
                let f_zero = 0 as $T;
                match n {
                    _ if n == f_zero => Unum::zero(),
                    n if n.is_nan() => Unum::nan(),
                    n if n.is_infinite() => Unum::infinity(),
                    _ => {
                        let counter = n.floor_log_2_abs() as i32;
                        let y_int : i64 = n.abs_val() as i64;
                        Unum {
                            env: PhantomData,
                            sign: n.is_sign_positive(),
                            exp_bits: (counter + 2_i32.pow((n.min_exp_bits() as u32) - 1) -1) as u32,
                            frac_bits: if counter == 0 {0} else {(y_int - 2_i64.pow(counter as u32)) as u32},
                            ubit: false,
                            exp_size: (n.min_exp_bits() - 1) as u8,
                            frac_size: (counter - if counter>0 {1} else {0}) as u8,
                        }
                    }
                }
            }
        }
    }
}

FromFloatForUnum!(f32);
FromFloatForUnum!(f64);



#[cfg(test)]
mod tests {
    use super::{Unum};
    use super::super::env;

    #[test]
    fn create_unum_from_i32() {
        let _ : Unum<env::Exp3Frac4> = 0_i32.into();
    }
    
    #[test]
    fn create_unum_from_i32_0() {
        let un : Unum<env::Exp3Frac4> = 0_i32.into();
        assert_eq!(un.sign, true);
        assert_eq!(un.exp_bits, 0);
        assert_eq!(un.frac_bits, 0);
        assert_eq!(un.ubit, false);
        assert_eq!(un.exp_size, 0);
        assert_eq!(un.frac_size, 0);
    }
    
    #[test]
    fn create_unum_from_i32_1() {
        let un = Unum::<env::Exp3Frac4>::from(1_i32);
        assert_eq!(un.sign, true);
        assert_eq!(un.exp_bits, 1);
        assert_eq!(un.frac_bits, 0);
        assert_eq!(un.ubit, false);
        assert_eq!(un.exp_size, 1);
        assert_eq!(un.frac_size, 0);
    }
    #[test]
    fn create_unum_from_i32_neg_1() {
        let un = Unum::<env::Exp3Frac4>::from(-1_i32);
        assert_eq!(un.sign, false);
        assert_eq!(un.exp_bits, 1);
        assert_eq!(un.frac_bits, 0);
        assert_eq!(un.ubit, false);
        assert_eq!(un.exp_size, 1);
        assert_eq!(un.frac_size, 0);
    }
    
    #[test]
    fn create_unum_from_i32_509() {
        let un = Unum::<env::Exp3Frac4>::from(509_i32);
        assert_eq!(un.sign, true);
        assert_eq!(un.exp_bits, 15); // actually 8 = 15 - (15-1)/2
        assert_eq!(un.frac_bits, 253); // fits inside 7 bits!
        assert_eq!(un.ubit, false);
        assert_eq!(un.exp_size, 3); // 3+1, so actually 4 bits
        assert_eq!(un.frac_size, 7); // actually 8 = 7 + 1 
    }
    
    #[test]
    fn create_unum_from_i32_neg_509() {
        let un = Unum::<env::Exp3Frac4>::from(-509_i32);
        assert_eq!(un.sign, false);
        assert_eq!(un.exp_bits, 15); // actually 8 = 15 - (15-1)/2
        assert_eq!(un.frac_bits, 253); // fits inside 7 bits!
        assert_eq!(un.ubit, false);
        assert_eq!(un.exp_size, 3); // 3+1, so actually 4 bits
        assert_eq!(un.frac_size, 7); // actually 8 = 7 + 1 
    }
    
    #[test]
    #[should_panic]
    fn create_unum_from_i32_old_67_867_967() {
        let _ = Unum::<env::Exp3Frac4>::from_i32_old(67_867_967);
    }
    
    #[test]
    fn create_unum_from_i32_67_867_967() {
        let un = Unum::<env::Exp3Frac4>::from(67_867_967_i32);
        assert_eq!(un.sign, true);
        assert_eq!(un.exp_bits, 57); // actually 26 = 57 - (63-1)/2
        assert_eq!(un.frac_bits, 759_103); // fits inside 7 bits!
        assert_eq!(un.ubit, false);
        assert_eq!(un.exp_size, 5); // 5+1, so actually 6 bits
        assert_eq!(un.frac_size, 25); // actually 26 = 25 + 1 
    }
 
    #[test]
    fn create_unum_from_i32_neg_67_867_967() {
        let un = Unum::<env::Exp3Frac4>::from(-67_867_967_i32);
        assert_eq!(un.sign, false);
        assert_eq!(un.exp_bits, 57); // actually 26 = 57 - (63-1)/2
        assert_eq!(un.frac_bits, 759_103); // fits inside 7 bits!
        assert_eq!(un.ubit, false);
        assert_eq!(un.exp_size, 5); // 5+1, so actually 6 bits
        assert_eq!(un.frac_size, 25); // actually 26 = 25 + 1 
    }

}