use serde::{Deserialize, Serialize};
pub const FPU_80_BITS_MAX: u128 = (1u128 << 80) - 1;
pub const REAL_INDEFINITE: u128 = 0xffff_c000_0000_0000_0000 & FPU_80_BITS_MAX;
pub const QNAN: u128 = 0x7fff_c000_0000_0000_0000 & FPU_80_BITS_MAX;
pub const F80_PI: u128 = 0x4000c90fdaa22168c234 & FPU_80_BITS_MAX;
pub const SIGN_MASK: u128 = 1 << 79;
pub const EXP_MASK: u128 = 0x7FFF;
pub const EXP_MASK2: u128 = 0x7FFF << 64;
pub const MANTISSA_MASK: u128 = (1u128 << 64) - 1;
pub const MANTISSA_MASK_NOINT: u128 = 0x7FFF_FFFF_FFFF_FFFF;
pub const INT_BIT_MASK: u128 = 1 << 63;
pub const INT_BIT_MASK64: u64 = 1 << 63;
pub const BCD_SIGN_POSITIVE: u8 = 0x0A;
pub const BCD_SIGN_NEGATIVE: u8 = 0x0B;
pub const F64_EXP_BIAS: i32 = 1023;
pub const F80_EXP_BIAS: i32 = 16383;
pub const MANTISSA_BITS: u32 = 64;
pub const SIGN_SHIFT: u32 = 79;
pub const EXP_SHIFT: u32 = 64;
pub const INT_BIT_SHIFT: u32 = 63;
#[derive(Copy, Clone, Serialize, Deserialize)]
pub struct F80 {
pub st: u128,
}
impl F80 {
pub fn new() -> Self {
F80 { st: 0 }
}
pub fn PI() -> Self {
F80 { st: F80_PI }
}
pub fn QNaN() -> Self {
F80 { st: QNAN }
}
pub fn set_PI(&mut self) {
self.st = F80_PI;
}
pub fn set_QNaN(&mut self) {
self.st = QNAN;
}
pub fn set_real_indefinite(&mut self) {
self.st = REAL_INDEFINITE;
}
pub fn is_invalid(&self) -> bool {
let exp = self.get_exponent();
let frac = self.get_fraction();
exp == 0x7FFF && frac != 0
}
pub fn is_empty(&self) -> bool {
self.is_zero() && self.is_invalid()
}
pub fn set_bytes(&mut self, bytes: &[u8; 10]) {
let mut val: u128 = 0;
for (i, &b) in bytes.iter().enumerate() {
val |= (b as u128) << (8 * i);
}
self.st = val & FPU_80_BITS_MAX;
}
pub fn get_bytes(&self) -> [u8; 10] {
let mut bytes = [0u8; 10];
for i in 0..10 {
bytes[i] = ((self.st >> (8 * i)) & 0xFF) as u8;
}
bytes
}
pub fn get_round_f64(&self, decimals: u32) -> f64 {
let value = self.get_f64();
let factor = 10f64.powi(decimals as i32);
(value * factor).round() / factor
}
pub fn get(&self) -> u128 {
self.st & FPU_80_BITS_MAX
}
pub fn set(&mut self, value: u128) {
self.st = value & FPU_80_BITS_MAX;
}
pub fn fix(&mut self) {
self.st = self.st & FPU_80_BITS_MAX;
}
pub fn is_negative(&self) -> bool {
self.st & SIGN_MASK != 0
}
pub fn get_sign(&self) -> bool {
(self.st >> SIGN_SHIFT) & 1 != 0
}
pub fn neg(&mut self) {
self.st ^= SIGN_MASK;
}
pub fn set_sign(&mut self, sign: bool) {
self.st = (self.st & !SIGN_MASK) | ((sign as u128) << 79);
}
pub fn is_zero(&self) -> bool {
let exponent = (self.st >> 64) & 0x7FFF;
let mantissa = self.st & ((1u128 << 64) - 1);
exponent == 0 && mantissa == 0
}
pub fn get_integer_bit(&self) -> u64 {
((self.st >> INT_BIT_SHIFT) & 1) as u64
}
pub fn get_fraction(&self) -> u64 {
(self.st & ((1u128 << 63) - 1)) as u64
}
pub fn get_exponent(&self) -> u16 {
((self.st >> EXP_SHIFT) & 0x7FFF) as u16
}
pub fn set_exponent(&mut self, exponent: u16) {
self.st = (self.st & !EXP_MASK2) | ((exponent as u128) << 64);
}
pub fn get_mantissa(&self) -> u64 {
(self.get_integer_bit() << 63) | self.get_fraction()
}
pub fn set_mantissa(&mut self, mantissa: u64) {
let int_bit = (mantissa >> 63) as u128;
let fraction = (mantissa & 0x7FFF_FFFF_FFFF_FFFF) as u128;
self.st &= !((1u128 << INT_BIT_SHIFT) | ((1u128 << 63) - 1));
self.st |= (int_bit << INT_BIT_SHIFT) | fraction;
}
fn get_mantissa_with_integer_bit(&self) -> u64 {
let mantissa = (self.st & MANTISSA_MASK_NOINT) >> 0;
let int_bit = ((self.st & INT_BIT_MASK) >> 63) as u64;
(mantissa as u64) | (int_bit << 63)
}
fn normalize_add(&self, mantissa: u64, exponent: u16) -> (u64, u16) {
let mut man = mantissa;
let mut exp = exponent;
if man == 0 {
return (0, 0);
}
while (man & INT_BIT_MASK64) == 0 {
man <<= 1;
exp -= 1;
}
(man, exp)
}
pub fn add(&mut self, b: F80) {
let a_sign = self.get_sign();
let b_sign = b.get_sign();
let mut a_exp = self.get_exponent();
let b_exp = b.get_exponent();
let mut a_man = self.get_mantissa() as u128;
let mut b_man = b.get_mantissa() as u128;
if a_exp > b_exp {
let shift = (a_exp - b_exp) as u32;
b_man >>= shift;
} else if b_exp > a_exp {
let shift = (b_exp - a_exp) as u32;
a_man >>= shift;
a_exp = b_exp;
}
let mut result_sign;
let mut result_exp = a_exp;
let mut result_man: u128;
if a_sign == b_sign {
result_man = a_man + b_man;
if (result_man & (1u128 << 64)) != 0 {
result_man >>= 1;
result_exp += 1;
}
result_sign = a_sign;
} else {
if a_man >= b_man {
result_man = a_man - b_man;
result_sign = a_sign;
} else {
result_man = b_man - a_man;
result_sign = b_sign;
}
let (norm_man, norm_exp) = self.normalize_add(result_man as u64, result_exp);
result_man = norm_man as u128;
result_exp = norm_exp;
if result_man == 0 {
result_sign = false;
result_exp = 0;
}
}
self.set_sign(result_sign);
self.set_exponent(result_exp);
self.set_mantissa(result_man as u64);
}
pub fn sub(&mut self, b: F80) {
let a_sign = self.get_sign();
let b_sign = b.get_sign();
let mut a_exp = self.get_exponent();
let b_exp = b.get_exponent();
let mut a_man = self.get_mantissa() as u128;
let mut b_man = b.get_mantissa() as u128;
if a_exp > b_exp {
let shift = (a_exp - b_exp) as u32;
b_man >>= shift;
} else if b_exp > a_exp {
let shift = (b_exp - a_exp) as u32;
a_man >>= shift;
a_exp = b_exp;
}
let mut result_sign;
let mut result_exp = a_exp;
let mut result_man: u128;
if a_sign != b_sign {
result_man = a_man + b_man;
if (result_man & (1u128 << 64)) != 0 {
result_man >>= 1;
result_exp += 1;
}
result_sign = a_sign;
} else {
if a_man >= b_man {
result_man = a_man - b_man;
result_sign = a_sign;
} else {
result_man = b_man - a_man;
result_sign = !a_sign;
}
let (norm_man, norm_exp) = self.normalize_sub(result_man as u64, result_exp);
result_man = norm_man as u128;
result_exp = norm_exp;
if result_man == 0 {
result_sign = false; result_exp = 0;
}
}
self.set_sign(result_sign);
self.set_exponent(result_exp);
self.set_mantissa(result_man as u64);
}
fn normalize_sub(&self, mut mant: u64, mut exp: u16) -> (u64, u16) {
while mant != 0 && (mant & (1 << 63)) == 0 {
mant <<= 1;
exp -= 1;
}
(mant, exp)
}
pub fn is_integer(&self) -> bool {
self.get_mantissa() == 0
}
pub fn is_normal(&self) -> bool {
let exponent = (self.st >> 64) & 0x7FFF;
exponent != 0 && exponent != 0x7FFF
}
pub fn bit_integer(&self) -> bool {
(self.st & INT_BIT_MASK) & 1 == 1
}
pub fn is_denormal(&self) -> bool {
let exponent = (self.st >> 64) & 0x7FFF;
exponent == 0
}
pub fn is_infinite(&self) -> bool {
let exponent = (self.st >> 64) & 0x7FFF;
let mantissa = self.st & ((1u128 << 64) - 1);
exponent == 0x7FFF && mantissa == 0
}
pub fn is_nan(&self) -> bool {
let exponent = (self.st >> 64) & 0x7FFF;
let mantissa = self.st & MANTISSA_MASK;
exponent == 0x7FFF && mantissa != 0
}
pub fn to_bcd_packed(&self) -> [u8; 10] {
let mut val = self.to_integer_u128();
let mut bcd = [0u8; 10];
for i in 0..9 {
let lo = (val % 10) as u8;
val /= 10;
let hi = (val % 10) as u8;
val /= 10;
bcd[i] = (hi << 4) | lo;
}
bcd[9] = if self.is_negative() {
BCD_SIGN_NEGATIVE
} else {
BCD_SIGN_POSITIVE
};
bcd
}
pub fn from_bcd_packed(&mut self, bcd: &[u8; 10]) {
let mut value: u128 = 0;
for i in (0..9).rev() {
let byte = bcd[i];
let hi = (byte >> 4) & 0x0F;
let lo = byte & 0x0F;
assert!(hi <= 9 && lo <= 9, "Invalid BCD digit");
value = value * 100 + (hi as u128) * 10 + (lo as u128);
}
let is_negative = match bcd[9] & 0x0F {
BCD_SIGN_NEGATIVE => true,
BCD_SIGN_POSITIVE => false,
_ => panic!("Invalid BCD sign"),
};
self.st = F80::encode_from_u128(value, is_negative);
}
pub fn to_integer_u128(&self) -> u128 {
let exp = self.get_exponent();
if exp == 0 || exp == 0x7FFF {
return 0; }
let bias = 16383;
let actual_exp = exp as i32 - bias;
if actual_exp < 0 {
return 0; }
let mantissa = self.get_mantissa_with_integer_bit() as u128;
if actual_exp > 63 {
mantissa << (actual_exp as u32 - 63)
} else {
mantissa >> (63 - actual_exp) as u32
}
}
pub fn encode_from_u128(value: u128, is_negative: bool) -> u128 {
if value == 0 {
return if is_negative { 1u128 << 79 } else { 0 };
}
let msb = 127 - value.leading_zeros() as u16;
let exponent = 16383 + msb;
let shift = msb as i32 - 63;
let mantissa = if shift > 0 {
value >> shift
} else {
value << (-shift) as u32
};
let sign_bit = if is_negative { 1u128 << 79 } else { 0 };
let exp_bits = (exponent as u128) << 64;
let mantissa_bits = mantissa & 0xFFFFFFFFFFFFFFFF;
sign_bit | exp_bits | mantissa_bits
}
pub fn set_f64(&mut self, value: f64) {
let bits = value.to_bits();
let sign = (bits >> 63) & 1;
let exp = ((bits >> 52) & 0x7FF) as u16;
let mantissa = bits & 0xFFFFFFFFFFFFF;
let st = if exp == 0 {
(sign as u128) << 79
} else if exp == 0x7FF {
let is_nan = mantissa != 0;
let extended_exp = 0x7FFFu128;
let extended_mantissa = (mantissa as u128) << 11;
let nan_bit = if is_nan { 1u128 << 62 } else { 0 }; ((sign as u128) << 79) | (extended_exp << 64) | extended_mantissa | nan_bit
} else {
let adjusted_exp = (exp as i32 - F64_EXP_BIAS) + F80_EXP_BIAS;
let extended_exp = adjusted_exp as u128;
let full_mantissa = ((1u64 << 52) | mantissa) as u128; let extended_mantissa = full_mantissa << 11; ((sign as u128) << 79) | (extended_exp << 64) | extended_mantissa
};
self.set(st); }
pub fn get_f64(&self) -> f64 {
let value = self.get();
let sign = ((value >> 79) & 1) as u64;
let exp = ((value >> 64) & 0x7FFF) as u16;
let mantissa = value & 0xFFFFFFFFFFFFFFFF;
let f64_bits: u64 = if exp == 0 {
sign << 63
} else if exp == 0x7FFF {
let f64_mantissa = (mantissa >> 11) as u64;
let nan_mask = if f64_mantissa != 0 { 1 << 51 } else { 0 }; (sign << 63) | (0x7FF << 52) | f64_mantissa | nan_mask
} else {
let unbiased_exp = exp as i32 - F80_EXP_BIAS;
let f64_exp = unbiased_exp + F64_EXP_BIAS;
if f64_exp <= 0 {
sign << 63
} else if f64_exp >= 0x7FF {
(sign << 63) | (0x7FF << 52)
} else {
let f64_mantissa = ((mantissa >> 11) & 0xFFFFFFFFFFFFF) as u64;
(sign << 63) | ((f64_exp as u64) << 52) | f64_mantissa
}
};
f64::from_bits(f64_bits)
}
}