use std::ops::{Add, Sub, Mul, Div, AddAssign, SubAssign};
use std::cmp::Ordering;


#[derive(Debug, Copy, Clone)]
pub struct FiNum(u64);

impl FiNum {
    pub fn new_str(s: &str) -> Self {
        match s.parse::<f64>() {
            Ok(n) => Self::new((n*4294967296.0) as u64),
            Err(_e) => Self::zero(),
            }
        }
    pub fn new(value: u64) -> Self {
        FiNum(value)
	}
    pub fn new_i32(value: i32) -> Self {
        FiNum((value as u64)<<32)
	}
    pub fn zero() -> Self {
        FiNum(0u64)
	}
    pub fn one() -> Self {
        FiNum(1u64<<32)
        }
    pub fn infinity() -> Self {
        FiNum(u64::MAX)
        }
    pub fn is_tiny(self) -> bool {
        self.0>0u64 && self.0<=1u64
	}
    pub fn is_zero(self) -> bool {
        self.0==0
	}
    pub fn value(&self) -> u64 {
        self.0
	}
    pub fn recip(&self) -> Self {
        FiNum((0x8000000000000000u64/self.0)<<1)
        }
    pub fn fmt_pct2(&self) -> String {
        format!("{:>5.2}%", (100.0*(self.0 as f64))/((1u64<<32) as f64))
        }
    pub fn fmt_recip(&self) -> String {
       if *self<FiNum::one() { format!("1/{}",self.recip()) }
       else { format!("{}",self) }
       }
    pub fn serialize(&self) -> String {
        format!("{:X}",self.0)
	}
    pub fn new_deserialize(s: &str) -> Self {
        FiNum(u64::from_str_radix(s, 16).unwrap())
        }
    }

impl From<i32> for FiNum {
    fn from(value:i32) -> Self {
        FiNum::new((value as u64)<<32)
	}
    }

impl PartialEq for FiNum {
    fn eq(&self, other:&Self) -> bool {
        self.0==other.0
	}
    }

impl Eq for FiNum { }

impl PartialOrd for FiNum {
    fn partial_cmp(&self, other:&Self) -> Option<Ordering> {
        self.0.partial_cmp(&other.0)
        }
    }

impl Ord for FiNum {
    fn cmp(&self, other:&Self) -> Ordering {
        self.0.cmp(&other.0)
	}
    }

impl Add for FiNum {
    type Output=Self;
    fn add(self, other: Self) -> Self {
        FiNum(self.0+other.0)
	}
    }

impl AddAssign for FiNum {
    fn add_assign(&mut self, other: Self) {
        self.0+=other.0;
	}
    }

impl Sub for FiNum {
    type Output=Self;
    fn sub(self, other: Self) -> Self {
        FiNum(self.0-other.0)
	}
    }

impl SubAssign for FiNum {
    fn sub_assign(&mut self, other: Self) {
        self.0-=other.0;
	}
    }

impl Mul for FiNum {
    type Output=Self;
    fn mul(self, other: Self) -> Self {
        FiNum(((self.value() as u128)*(other.value() as u128)>>32) as u64)
	}
    }

impl Div for FiNum {
   type Output=Self;
   fn div(self,other:Self) -> Self {
	 let ip=(self.value() as u128)/(other.value() as u128);
	 let rp=(self.value() as u128)%(other.value() as u128);
	 let fp=(rp<<32)/(other.value() as u128);
	 FiNum(((ip<<32)|fp) as u64)
       }
   }

    
impl std::fmt::Display for FiNum {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
//        write!(f, "{:08X}.{:08X}", self.0>>32,self.0&0xFFFFFFFF)
        write!(f, "{:.8}", (self.0 as f64)/((1u64<<32) as f64))
    }
}

