use super::errors::ErrorCodes;
use anyhow::Result;
const COEFFICIENT_SIZE_DEBT_FACTOR: u8 = 35;
const EXPONENT_SIZE_DEBT_FACTOR: u8 = 15;
const EXPONENT_MAX_DEBT_FACTOR: u64 = (1 << EXPONENT_SIZE_DEBT_FACTOR) - 1;
const DECIMALS_DEBT_FACTOR: u64 = 16384;
pub const MAX_MASK_DEBT_FACTOR: u64 =
(1 << (COEFFICIENT_SIZE_DEBT_FACTOR + EXPONENT_SIZE_DEBT_FACTOR)) - 1;
#[allow(dead_code)]
const COEFFICIENT_MAX: u64 = (1 << COEFFICIENT_SIZE_DEBT_FACTOR) - 1;
#[allow(dead_code)]
const COEFFICIENT_MIN: u64 = 1 << (COEFFICIENT_SIZE_DEBT_FACTOR - 1);
pub const PRECISION: u8 = 64;
pub const TWO_POWER_64: u128 = 1 << PRECISION;
const TWO_POWER_69_MINUS_1: u128 = (1 << 69) - 1;
const COEFFICIENT_PLUS_PRECISION: u8 = COEFFICIENT_SIZE_DEBT_FACTOR + PRECISION; const COEFFICIENT_PLUS_PRECISION_MINUS_1: u8 = COEFFICIENT_PLUS_PRECISION - 1; const TWO_POWER_COEFFICIENT_PLUS_PRECISION_MINUS_1: u128 =
(1 << COEFFICIENT_PLUS_PRECISION_MINUS_1) - 1; const TWO_POWER_COEFFICIENT_PLUS_PRECISION_MINUS_1_MINUS_1: u128 =
(1 << (COEFFICIENT_PLUS_PRECISION_MINUS_1 - 1)) - 1;
pub fn mul_div_normal(normal: u64, big_number1: u64, big_number2: u64) -> Result<u64> {
if big_number1 == 0 || big_number2 == 0 {
return Ok(0);
}
let exponent1 = big_number1 & EXPONENT_MAX_DEBT_FACTOR;
let exponent2 = big_number2 & EXPONENT_MAX_DEBT_FACTOR;
if exponent2 < exponent1 {
return Err(ErrorCodes::BnError.into()); }
let net_exponent = exponent2 - exponent1;
if net_exponent < 129 {
let coefficient1 = big_number1 >> EXPONENT_SIZE_DEBT_FACTOR;
let coefficient2 = big_number2 >> EXPONENT_SIZE_DEBT_FACTOR;
let numerator: u128 = (normal as u128) * (coefficient1 as u128);
let denominator: u128 = (coefficient2 as u128) << net_exponent;
if denominator == 0 {
return Err(ErrorCodes::DivisionByZero.into());
}
let result = numerator / denominator;
if result > u64::MAX as u128 {
return Err(ErrorCodes::BnError.into());
}
Ok(result as u64)
} else {
Ok(0)
}
}
pub fn mul_div_big_number(big_number: u64, number1: u128) -> Result<u64> {
if big_number == 0 {
return Ok(0);
}
let coefficient = big_number >> EXPONENT_SIZE_DEBT_FACTOR;
let exponent = big_number & EXPONENT_MAX_DEBT_FACTOR;
let result_numerator: u128 = (coefficient as u128) * number1;
let mut diff: u8;
if result_numerator > TWO_POWER_COEFFICIENT_PLUS_PRECISION_MINUS_1 {
diff = COEFFICIENT_PLUS_PRECISION;
} else if result_numerator > TWO_POWER_COEFFICIENT_PLUS_PRECISION_MINUS_1_MINUS_1 {
diff = COEFFICIENT_PLUS_PRECISION_MINUS_1;
} else {
diff = most_significant_bit(result_numerator);
}
diff = diff.saturating_sub(COEFFICIENT_SIZE_DEBT_FACTOR);
let adjusted_coefficient = (result_numerator >> diff) as u64;
let result_exponent = exponent.saturating_add(diff as u64);
if result_exponent > PRECISION as u64 {
let final_exponent = result_exponent - PRECISION as u64;
if final_exponent > EXPONENT_MAX_DEBT_FACTOR {
return Err(ErrorCodes::BnError.into());
}
Ok((adjusted_coefficient << EXPONENT_SIZE_DEBT_FACTOR) | final_exponent)
} else {
Err(ErrorCodes::BnError.into())
}
}
pub fn mul_big_number(big_number1: u64, big_number2: u64) -> Result<u64> {
let coefficient1: u64 = big_number1 >> EXPONENT_SIZE_DEBT_FACTOR;
let coefficient2: u64 = big_number2 >> EXPONENT_SIZE_DEBT_FACTOR;
let exponent1: u64 = big_number1 & EXPONENT_MAX_DEBT_FACTOR;
let exponent2: u64 = big_number2 & EXPONENT_MAX_DEBT_FACTOR;
let res_coefficient: u128 = (coefficient1 as u128) * (coefficient2 as u128);
let overflow_len = if res_coefficient > TWO_POWER_69_MINUS_1 {
COEFFICIENT_SIZE_DEBT_FACTOR as u64
} else {
(COEFFICIENT_SIZE_DEBT_FACTOR - 1) as u64
};
let adjusted_coefficient = (res_coefficient >> overflow_len) as u64;
let res_exponent = exponent1 + exponent2 + overflow_len;
if res_exponent < DECIMALS_DEBT_FACTOR {
return Err(ErrorCodes::BnError.into());
}
let final_exponent = res_exponent - DECIMALS_DEBT_FACTOR;
if final_exponent > EXPONENT_MAX_DEBT_FACTOR {
return Ok(MAX_MASK_DEBT_FACTOR);
}
Ok((adjusted_coefficient << EXPONENT_SIZE_DEBT_FACTOR) | final_exponent)
}
pub fn div_big_number(big_number1: u64, big_number2: u64) -> Result<u64> {
if big_number1 == 0 {
return Ok(0);
}
if big_number2 == 0 {
return Err(ErrorCodes::DivisionByZero.into());
}
let coefficient1 = big_number1 >> EXPONENT_SIZE_DEBT_FACTOR;
let coefficient2 = big_number2 >> EXPONENT_SIZE_DEBT_FACTOR;
let exponent1 = big_number1 & EXPONENT_MAX_DEBT_FACTOR;
let exponent2 = big_number2 & EXPONENT_MAX_DEBT_FACTOR;
if coefficient2 == 0 {
return Err(ErrorCodes::DivisionByZero.into());
}
let res_coefficient: u128 =
((coefficient1 as u128) << PRECISION as u128) / (coefficient2 as u128);
let overflow_len = if (res_coefficient >> PRECISION as u128) == 1 {
(PRECISION + 1) as u64
} else {
PRECISION as u64
};
let adjusted_overflow_len = overflow_len - COEFFICIENT_SIZE_DEBT_FACTOR as u64;
let adjusted_coefficient = (res_coefficient >> adjusted_overflow_len) as u64;
let addition_part = exponent1 + DECIMALS_DEBT_FACTOR + adjusted_overflow_len;
let subtraction_part = exponent2 + PRECISION as u64;
if addition_part > subtraction_part {
let final_exponent = addition_part - subtraction_part;
if final_exponent > EXPONENT_MAX_DEBT_FACTOR {
return Err(ErrorCodes::BnError.into());
}
Ok((adjusted_coefficient << EXPONENT_SIZE_DEBT_FACTOR) | final_exponent)
} else {
Err(ErrorCodes::BnError.into())
}
}
pub fn most_significant_bit(normal: u128) -> u8 {
if normal == 0 {
return 0;
}
128 - (normal.leading_zeros() as u8)
}
#[allow(dead_code)]
fn create_big_number(coefficient: u64, exponent: u64) -> u64 {
(coefficient << EXPONENT_SIZE_DEBT_FACTOR) | exponent
}
#[allow(dead_code)]
fn extract_coefficient(big_number: u64) -> u64 {
big_number >> EXPONENT_SIZE_DEBT_FACTOR
}
#[allow(dead_code)]
fn extract_exponent(big_number: u64) -> u64 {
big_number & EXPONENT_MAX_DEBT_FACTOR
}