#[allow(unused_imports)]
use super::{BinaryStorage, ComputeStorage, StackValue, StackEvaluator, DECIMAL_DP_PROMOTION_THRESHOLD};
use super::compute::*;
#[allow(unused_imports)]
use super::conversion::{to_binary_storage, reduce_decimal_to_rational};
#[allow(unused_imports)]
use super::domain::{ternary_to_rational, ternary_to_storage, decimal_from_storage, decimal_to_storage, binary_to_storage};
#[allow(unused_imports)]
use super::formatting::pow10_i256;
#[cfg(table_format = "q256_256")]
#[allow(unused_imports)]
use super::formatting::pow10_i512;
use crate::fixed_point::domains::balanced_ternary::ternary_types::{UniversalTernaryFixed, TernaryRaw};
use crate::fixed_point::i256::I256;
use crate::fixed_point::i512::I512;
#[allow(unused_imports)]
use crate::fixed_point::I1024;
use crate::fixed_point::universal::tier_types::CompactShadow;
use crate::fixed_point::domains::symbolic::rational::rational_number::{RationalNumber, OverflowDetected};
#[cfg(table_format = "q256_256")]
use crate::fixed_point::domains::binary_fixed::transcendental::ln_binary_i1024;
#[cfg(table_format = "q128_128")]
use crate::fixed_point::domains::binary_fixed::transcendental::{exp_binary_i512, ln_binary_i512};
#[cfg(table_format = "q64_64")]
use crate::fixed_point::domains::binary_fixed::transcendental::{exp_binary_i256, ln_binary_i256};
#[cfg(table_format = "q32_32")]
use crate::fixed_point::domains::binary_fixed::transcendental::{exp_binary_i128, ln_binary_i128};
#[cfg(table_format = "q16_16")]
use crate::fixed_point::domains::binary_fixed::transcendental::{exp_binary_i64, ln_binary_i64};
impl StackEvaluator {
pub(crate) fn exp_at_compute_tier(&self, compute_val: ComputeStorage, storage_tier: u8) -> Result<StackValue, OverflowDetected> {
#[cfg(table_format = "q256_256")]
{
use crate::fixed_point::domains::binary_fixed::transcendental::exp_binary_i1024;
let result = exp_binary_i1024(compute_val);
Ok(StackValue::BinaryCompute(storage_tier, result, CompactShadow::None))
}
#[cfg(table_format = "q128_128")]
{
let result = exp_binary_i512(compute_val);
Ok(StackValue::BinaryCompute(storage_tier, result, CompactShadow::None))
}
#[cfg(table_format = "q64_64")]
{
let result = exp_binary_i256(compute_val);
Ok(StackValue::BinaryCompute(storage_tier, result, CompactShadow::None))
}
#[cfg(table_format = "q32_32")]
{
let result = exp_binary_i128(compute_val);
Ok(StackValue::BinaryCompute(storage_tier, result, CompactShadow::None))
}
#[cfg(table_format = "q16_16")]
{
let result = exp_binary_i64(compute_val);
Ok(StackValue::BinaryCompute(storage_tier, result, CompactShadow::None))
}
}
pub(crate) fn try_decimal_compute(&self, value: &StackValue) -> Option<ComputeStorage> {
use crate::fixed_point::domains::decimal_fixed::transcendental::decimal_upscale_to_compute;
match value {
StackValue::DecimalCompute(_, val, _) => Some(*val),
StackValue::Decimal(dp, scaled, _) => decimal_upscale_to_compute(*scaled, *dp).ok(),
_ => None,
}
}
pub(crate) fn evaluate_exp(&mut self, value: StackValue) -> Result<StackValue, OverflowDetected> {
let storage_tier = self.profile_max_binary_tier();
if let Some(dec_compute) = self.try_decimal_compute(&value) {
use crate::fixed_point::domains::decimal_fixed::transcendental::decimal_exp;
let result = decimal_exp(dec_compute)?;
return Ok(StackValue::DecimalCompute(storage_tier, result, CompactShadow::None));
}
let compute_val = self.to_compute_storage(&value)?;
self.exp_at_compute_tier(compute_val, storage_tier)
}
pub(crate) fn ln_at_compute_tier(&self, compute_val: ComputeStorage, storage_tier: u8) -> Result<StackValue, OverflowDetected> {
if compute_is_negative(&compute_val) || compute_is_zero(&compute_val) {
return Err(OverflowDetected::DomainError);
}
#[cfg(table_format = "q256_256")]
{
let result = ln_binary_i1024(compute_val);
Ok(StackValue::BinaryCompute(storage_tier, result, CompactShadow::None))
}
#[cfg(table_format = "q128_128")]
{
let result = ln_binary_i512(compute_val);
Ok(StackValue::BinaryCompute(storage_tier, result, CompactShadow::None))
}
#[cfg(table_format = "q64_64")]
{
let result = ln_binary_i256(compute_val);
Ok(StackValue::BinaryCompute(storage_tier, result, CompactShadow::None))
}
#[cfg(table_format = "q32_32")]
{
let result = ln_binary_i128(compute_val);
Ok(StackValue::BinaryCompute(storage_tier, result, CompactShadow::None))
}
#[cfg(table_format = "q16_16")]
{
let result = ln_binary_i64(compute_val);
Ok(StackValue::BinaryCompute(storage_tier, result, CompactShadow::None))
}
}
pub(crate) fn evaluate_ln(&mut self, value: StackValue) -> Result<StackValue, OverflowDetected> {
let storage_tier = self.profile_max_binary_tier();
if let Some(dec_compute) = self.try_decimal_compute(&value) {
use crate::fixed_point::domains::decimal_fixed::transcendental::decimal_ln;
let result = decimal_ln(dec_compute)?;
return Ok(StackValue::DecimalCompute(storage_tier, result, CompactShadow::None));
}
let compute_val = self.to_compute_storage(&value)?;
self.ln_at_compute_tier(compute_val, storage_tier)
}
pub(crate) fn evaluate_sqrt(&mut self, value: StackValue) -> Result<StackValue, OverflowDetected> {
let storage_tier = self.profile_max_binary_tier();
if let Some(dec_compute) = self.try_decimal_compute(&value) {
use crate::fixed_point::domains::decimal_fixed::transcendental::decimal_sqrt;
let result = decimal_sqrt(dec_compute)?;
return Ok(StackValue::DecimalCompute(storage_tier, result, CompactShadow::None));
}
let compute_val = self.to_compute_storage(&value)?;
if compute_is_negative(&compute_val) {
return Err(OverflowDetected::DomainError);
}
let result = sqrt_at_compute_tier(compute_val);
Ok(StackValue::BinaryCompute(storage_tier, result, CompactShadow::None))
}
pub(crate) fn evaluate_pow(&mut self, base: StackValue, exponent: StackValue) -> Result<StackValue, OverflowDetected> {
if let Some((exp_num, exp_den)) = exponent.shadow().as_rational() {
if exp_den == 1 && exp_num.unsigned_abs() <= 1000 {
return self.pow_integer(base, exp_num as i64);
}
}
let ln_base = self.evaluate_ln(base)?;
let product = self.multiply_values(exponent, ln_base)?;
self.evaluate_exp(product)
}
pub(crate) fn pow_integer(&mut self, base: StackValue, exp: i64) -> Result<StackValue, OverflowDetected> {
let negative = exp < 0;
let mut n = exp.unsigned_abs();
if n == 0 {
return Ok(self.make_int_like(&base, 1));
}
let mut b = self.to_binary_value(&base)?;
let mut result = self.make_int_like(&b, 1);
while n > 0 {
if n & 1 == 1 {
result = self.multiply_values(result, b.clone())?;
}
n >>= 1;
if n > 0 {
b = self.multiply_values(b.clone(), b)?;
}
}
if negative {
let one = self.make_int_like(&result, 1);
result = self.binary_divide(one, result)?;
}
Ok(result)
}
pub(crate) fn make_binary_int(&self, value: i128) -> StackValue {
let tier = self.profile_max_binary_tier();
#[cfg(table_format = "q256_256")]
{ StackValue::Binary(tier, I512::from_i128(value) << 256, CompactShadow::from_rational(value, 1)) }
#[cfg(table_format = "q128_128")]
{ StackValue::Binary(tier, I256::from_i128(value) << 128, CompactShadow::from_rational(value, 1)) }
#[cfg(table_format = "q64_64")]
{ StackValue::Binary(tier, value << 64, CompactShadow::from_rational(value, 1)) }
#[cfg(table_format = "q32_32")]
{ StackValue::Binary(tier, (value as i64) << 32, CompactShadow::from_rational(value, 1)) }
#[cfg(table_format = "q16_16")]
{
use crate::fixed_point::frac_config;
StackValue::Binary(tier, (value as i32) << frac_config::FRAC_BITS, CompactShadow::from_rational(value, 1))
}
}
pub(crate) fn make_int_like(&self, reference: &StackValue, value: i128) -> StackValue {
match reference {
StackValue::DecimalCompute(..) | StackValue::Decimal(..) => {
use crate::fixed_point::domains::decimal_fixed::transcendental::decimal_compute_from_int;
let tier = self.profile_max_binary_tier();
StackValue::DecimalCompute(
tier,
decimal_compute_from_int(value as i64),
CompactShadow::from_rational(value, 1),
)
}
_ => self.make_binary_int(value),
}
}
pub(crate) fn to_binary_value(&mut self, val: &StackValue) -> Result<StackValue, OverflowDetected> {
match val {
StackValue::BinaryCompute(..) => Ok(val.clone()),
StackValue::DecimalCompute(..) => Ok(val.clone()),
StackValue::Decimal(dp, scaled, shadow) => {
use crate::fixed_point::domains::decimal_fixed::transcendental::decimal_upscale_to_compute;
let dec_compute = decimal_upscale_to_compute(*scaled, *dp)?;
let tier = self.profile_max_binary_tier();
Ok(StackValue::DecimalCompute(tier, dec_compute, shadow.clone()))
}
_ => {
let compute = self.to_compute_storage(val)?;
let tier = self.profile_max_binary_tier();
Ok(StackValue::BinaryCompute(tier, compute, val.shadow()))
}
}
}
pub(crate) fn halve_binary(&self, value: StackValue) -> Result<StackValue, OverflowDetected> {
match value {
StackValue::BinaryCompute(tier, val, _) => {
Ok(StackValue::BinaryCompute(tier, compute_halve(val), CompactShadow::None))
}
StackValue::DecimalCompute(tier, val, _) => {
use crate::fixed_point::domains::decimal_fixed::transcendental::decimal_compute_halve;
Ok(StackValue::DecimalCompute(tier, decimal_compute_halve(val), CompactShadow::None))
}
StackValue::Binary(tier, val, _) => {
#[cfg(table_format = "q256_256")]
{ Ok(StackValue::Binary(tier, val >> 1, CompactShadow::None)) }
#[cfg(table_format = "q128_128")]
{ Ok(StackValue::Binary(tier, val >> 1, CompactShadow::None)) }
#[cfg(table_format = "q64_64")]
{ Ok(StackValue::Binary(tier, val >> 1, CompactShadow::None)) }
#[cfg(table_format = "q32_32")]
{ Ok(StackValue::Binary(tier, val >> 1, CompactShadow::None)) }
#[cfg(table_format = "q16_16")]
{ Ok(StackValue::Binary(tier, val >> 1, CompactShadow::None)) }
}
other => {
let _two = self.make_binary_int(2);
let binary_val = self.to_binary_storage(&other)?;
let tier = self.profile_max_binary_tier();
#[cfg(table_format = "q256_256")]
{ Ok(StackValue::Binary(tier, binary_val >> 1, CompactShadow::None)) }
#[cfg(table_format = "q128_128")]
{ Ok(StackValue::Binary(tier, binary_val >> 1, CompactShadow::None)) }
#[cfg(table_format = "q64_64")]
{ Ok(StackValue::Binary(tier, binary_val >> 1, CompactShadow::None)) }
#[cfg(table_format = "q32_32")]
{ Ok(StackValue::Binary(tier, binary_val >> 1, CompactShadow::None)) }
#[cfg(table_format = "q16_16")]
{ Ok(StackValue::Binary(tier, binary_val >> 1, CompactShadow::None)) }
}
}
}
pub(crate) fn binary_divide(&self, left: StackValue, right: StackValue) -> Result<StackValue, OverflowDetected> {
use crate::fixed_point::domains::decimal_fixed::transcendental::{
decimal_compute_div, decimal_upscale_to_compute,
};
match (&left, &right) {
(StackValue::DecimalCompute(t, v1, _), StackValue::DecimalCompute(_, v2, _)) => {
return Ok(StackValue::DecimalCompute(*t, decimal_compute_div(*v1, *v2)?, CompactShadow::None));
}
(StackValue::DecimalCompute(t, v1, _), StackValue::Decimal(dp, scaled, _)) => {
let v2 = decimal_upscale_to_compute(*scaled, *dp)?;
return Ok(StackValue::DecimalCompute(*t, decimal_compute_div(*v1, v2)?, CompactShadow::None));
}
(StackValue::Decimal(dp, scaled, _), StackValue::DecimalCompute(t, v2, _)) => {
let v1 = decimal_upscale_to_compute(*scaled, *dp)?;
return Ok(StackValue::DecimalCompute(*t, decimal_compute_div(v1, *v2)?, CompactShadow::None));
}
_ => {}
}
match (&left, &right) {
(StackValue::BinaryCompute(t, v1, _), StackValue::BinaryCompute(_, v2, _)) => {
return Ok(StackValue::BinaryCompute(*t, compute_divide(*v1, *v2)?, CompactShadow::None));
}
(StackValue::BinaryCompute(t, v1, _), StackValue::Binary(_, v2, _)) => {
let v2_compute = upscale_to_compute(*v2);
return Ok(StackValue::BinaryCompute(*t, compute_divide(*v1, v2_compute)?, CompactShadow::None));
}
(StackValue::Binary(_, v1, _), StackValue::BinaryCompute(t, v2, _)) => {
let v1_compute = upscale_to_compute(*v1);
return Ok(StackValue::BinaryCompute(*t, compute_divide(v1_compute, *v2)?, CompactShadow::None));
}
(StackValue::BinaryCompute(t, v1, _), other) => {
let other_compute = self.to_compute_storage(other)?;
return Ok(StackValue::BinaryCompute(*t, compute_divide(*v1, other_compute)?, CompactShadow::None));
}
(other, StackValue::BinaryCompute(t, v2, _)) => {
let other_compute = self.to_compute_storage(other)?;
return Ok(StackValue::BinaryCompute(*t, compute_divide(other_compute, *v2)?, CompactShadow::None));
}
_ => {}
}
let num = self.to_binary_storage(&left)?;
let den = self.to_binary_storage(&right)?;
let tier = self.profile_max_binary_tier();
#[cfg(table_format = "q256_256")]
{
let num_wide = I1024::from_i512(num) << 256;
let den_wide = I1024::from_i512(den);
if den_wide == I1024::zero() { return Err(OverflowDetected::DivisionByZero); }
let result = (num_wide / den_wide).as_i512();
Ok(StackValue::Binary(tier, result, CompactShadow::None))
}
#[cfg(table_format = "q128_128")]
{
let num_wide = I512::from_i256(num) << 128;
let den_wide = I512::from_i256(den);
if den_wide == I512::zero() { return Err(OverflowDetected::DivisionByZero); }
let result = (num_wide / den_wide).as_i256();
Ok(StackValue::Binary(tier, result, CompactShadow::None))
}
#[cfg(table_format = "q64_64")]
{
let num_wide = I256::from_i128(num) << 64;
let den_wide = I256::from_i128(den);
if den_wide == I256::zero() { return Err(OverflowDetected::DivisionByZero); }
let result = (num_wide / den_wide).as_i128();
Ok(StackValue::Binary(tier, result, CompactShadow::None))
}
#[cfg(table_format = "q32_32")]
{
let num_wide = (num as i128) << 32;
let den_wide = den as i128;
if den_wide == 0 { return Err(OverflowDetected::DivisionByZero); }
let result = (num_wide / den_wide) as i64;
Ok(StackValue::Binary(tier, result, CompactShadow::None))
}
#[cfg(table_format = "q16_16")]
{
use crate::fixed_point::frac_config;
let num_wide = (num as i64) << frac_config::FRAC_BITS;
let den_wide = den as i64;
if den_wide == 0 { return Err(OverflowDetected::DivisionByZero); }
let result = (num_wide / den_wide) as i32;
Ok(StackValue::Binary(tier, result, CompactShadow::None))
}
}
pub(crate) fn evaluate_sinh(&mut self, value: StackValue) -> Result<StackValue, OverflowDetected> {
let exp_x = self.evaluate_exp(value.clone())?;
let neg_x = self.negate_value(value)?;
let exp_neg_x = self.evaluate_exp(neg_x)?;
let diff = self.subtract_values(exp_x, exp_neg_x)?;
self.halve_binary(diff)
}
pub(crate) fn evaluate_cosh(&mut self, value: StackValue) -> Result<StackValue, OverflowDetected> {
let exp_x = self.evaluate_exp(value.clone())?;
let neg_x = self.negate_value(value)?;
let exp_neg_x = self.evaluate_exp(neg_x)?;
let sum = self.add_values(exp_x, exp_neg_x)?;
self.halve_binary(sum)
}
pub(crate) fn evaluate_tanh(&mut self, value: StackValue) -> Result<StackValue, OverflowDetected> {
let value = self.to_binary_value(&value)?;
let two = self.make_int_like(&value, 2);
let two_x = self.multiply_values(two, value.clone())?;
let exp_2x = self.evaluate_exp(two_x)?;
let one = self.make_int_like(&value, 1);
let numerator = self.subtract_values(exp_2x.clone(), one.clone())?;
let denominator = self.add_values(exp_2x, one)?;
self.binary_divide(numerator, denominator)
}
pub(crate) fn evaluate_asinh(&mut self, value: StackValue) -> Result<StackValue, OverflowDetected> {
let value = self.to_binary_value(&value)?;
let x_sq = self.multiply_values(value.clone(), value.clone())?;
let one = self.make_int_like(&value, 1);
let x_sq_plus_1 = self.add_values(x_sq, one)?;
let sqrt_val = self.evaluate_sqrt(x_sq_plus_1)?;
let sum = self.add_values(value, sqrt_val)?;
self.evaluate_ln(sum)
}
pub(crate) fn evaluate_acosh(&mut self, value: StackValue) -> Result<StackValue, OverflowDetected> {
let binary_val = self.to_binary_storage(&value)?;
let one_binary = self.to_binary_storage(&self.make_binary_int(1))?;
if binary_val < one_binary { return Err(OverflowDetected::DomainError); }
let value = self.to_binary_value(&value)?;
let x_sq = self.multiply_values(value.clone(), value.clone())?;
let one = self.make_int_like(&value, 1);
let x_sq_minus_1 = self.subtract_values(x_sq, one)?;
let sqrt_val = self.evaluate_sqrt(x_sq_minus_1)?;
let sum = self.add_values(value, sqrt_val)?;
self.evaluate_ln(sum)
}
pub(crate) fn evaluate_atanh(&mut self, value: StackValue) -> Result<StackValue, OverflowDetected> {
let binary_val = self.to_binary_storage(&value)?;
let one_binary = self.to_binary_storage(&self.make_binary_int(1))?;
#[cfg(table_format = "q256_256")]
{
let neg_one = I512::zero() - one_binary;
if binary_val >= one_binary || binary_val <= neg_one {
return Err(OverflowDetected::DomainError);
}
}
#[cfg(table_format = "q128_128")]
{
let neg_one = I256::zero() - one_binary;
if binary_val >= one_binary || binary_val <= neg_one {
return Err(OverflowDetected::DomainError);
}
}
#[cfg(table_format = "q64_64")]
{
if binary_val >= one_binary || binary_val <= -one_binary {
return Err(OverflowDetected::DomainError);
}
}
#[cfg(table_format = "q32_32")]
{
if binary_val >= one_binary || binary_val <= -one_binary {
return Err(OverflowDetected::DomainError);
}
}
#[cfg(table_format = "q16_16")]
{
if binary_val >= one_binary || binary_val <= -one_binary {
return Err(OverflowDetected::DomainError);
}
}
let value = self.to_binary_value(&value)?;
let one = self.make_int_like(&value, 1);
let one_plus_x = self.add_values(one.clone(), value.clone())?;
let one_minus_x = self.subtract_values(one, value)?;
let ratio = self.binary_divide(one_plus_x, one_minus_x)?;
let ln_ratio = self.evaluate_ln(ratio)?;
self.halve_binary(ln_ratio)
}
pub(crate) fn evaluate_sin(&mut self, value: StackValue) -> Result<StackValue, OverflowDetected> {
let storage_tier = self.profile_max_binary_tier();
if let Some(dec_compute) = self.try_decimal_compute(&value) {
use crate::fixed_point::domains::decimal_fixed::transcendental::decimal_sin;
let result = decimal_sin(dec_compute)?;
return Ok(StackValue::DecimalCompute(storage_tier, result, CompactShadow::None));
}
let compute_val = self.to_compute_storage(&value)?;
let result = sin_at_compute_tier(compute_val);
Ok(StackValue::BinaryCompute(storage_tier, result, CompactShadow::None))
}
pub(crate) fn evaluate_cos(&mut self, value: StackValue) -> Result<StackValue, OverflowDetected> {
let storage_tier = self.profile_max_binary_tier();
if let Some(dec_compute) = self.try_decimal_compute(&value) {
use crate::fixed_point::domains::decimal_fixed::transcendental::decimal_cos;
let result = decimal_cos(dec_compute)?;
return Ok(StackValue::DecimalCompute(storage_tier, result, CompactShadow::None));
}
let compute_val = self.to_compute_storage(&value)?;
let result = cos_at_compute_tier(compute_val);
Ok(StackValue::BinaryCompute(storage_tier, result, CompactShadow::None))
}
pub(crate) fn evaluate_sincos(&mut self, value: StackValue) -> Result<(StackValue, StackValue), OverflowDetected> {
let storage_tier = self.profile_max_binary_tier();
if let Some(dec_compute) = self.try_decimal_compute(&value) {
use crate::fixed_point::domains::decimal_fixed::transcendental::decimal_sincos;
let (sin_result, cos_result) = decimal_sincos(dec_compute)?;
return Ok((
StackValue::DecimalCompute(storage_tier, sin_result, CompactShadow::None),
StackValue::DecimalCompute(storage_tier, cos_result, CompactShadow::None),
));
}
let compute_val = self.to_compute_storage(&value)?;
let (sin_result, cos_result) = sincos_at_compute_tier(compute_val);
Ok((
StackValue::BinaryCompute(storage_tier, sin_result, CompactShadow::None),
StackValue::BinaryCompute(storage_tier, cos_result, CompactShadow::None),
))
}
pub(crate) fn evaluate_sinhcosh(&mut self, value: StackValue) -> Result<(StackValue, StackValue), OverflowDetected> {
let storage_tier = self.profile_max_binary_tier();
if let Some(dec_compute) = self.try_decimal_compute(&value) {
use crate::fixed_point::domains::decimal_fixed::transcendental::decimal_sinhcosh;
let (sinh_result, cosh_result) = decimal_sinhcosh(dec_compute)?;
return Ok((
StackValue::DecimalCompute(storage_tier, sinh_result, CompactShadow::None),
StackValue::DecimalCompute(storage_tier, cosh_result, CompactShadow::None),
));
}
let compute_val = self.to_compute_storage(&value)?;
let (sinh_result, cosh_result) = sinhcosh_at_compute_tier(compute_val);
Ok((
StackValue::BinaryCompute(storage_tier, sinh_result, CompactShadow::None),
StackValue::BinaryCompute(storage_tier, cosh_result, CompactShadow::None),
))
}
pub(crate) fn evaluate_tan(&mut self, value: StackValue) -> Result<StackValue, OverflowDetected> {
let (sin_val, cos_val) = self.evaluate_sincos(value)?;
if let StackValue::BinaryCompute(_, c, _) = &cos_val {
if compute_is_zero(c) {
return Err(OverflowDetected::DomainError);
}
}
self.binary_divide(sin_val, cos_val)
}
pub(crate) fn evaluate_asin(&mut self, value: StackValue) -> Result<StackValue, OverflowDetected> {
let binary_val = self.to_binary_storage(&value)?;
let one_bs = self.to_binary_storage(&self.make_binary_int(1))?;
#[cfg(table_format = "q256_256")]
{
let abs_val = if binary_val < I512::zero() { I512::zero() - binary_val } else { binary_val };
if abs_val > one_bs { return Err(OverflowDetected::DomainError); }
}
#[cfg(table_format = "q128_128")]
{
let abs_val = if binary_val < I256::zero() { I256::zero() - binary_val } else { binary_val };
if abs_val > one_bs { return Err(OverflowDetected::DomainError); }
}
#[cfg(table_format = "q64_64")]
{
let abs_val = if binary_val < 0 { -binary_val } else { binary_val };
if abs_val > one_bs { return Err(OverflowDetected::DomainError); }
}
#[cfg(table_format = "q32_32")]
{
let abs_val = if binary_val < 0 { -binary_val } else { binary_val };
if abs_val > one_bs { return Err(OverflowDetected::DomainError); }
}
#[cfg(table_format = "q16_16")]
{
let abs_val = if binary_val < 0 { -binary_val } else { binary_val };
if abs_val > one_bs { return Err(OverflowDetected::DomainError); }
}
if binary_val == one_bs {
let storage_tier = self.profile_max_binary_tier();
let pi_half = pi_half_at_compute_tier();
return Ok(StackValue::BinaryCompute(storage_tier, pi_half, CompactShadow::None));
}
#[cfg(table_format = "q64_64")]
let neg_one_bs: i128 = -one_bs;
#[cfg(table_format = "q128_128")]
let neg_one_bs = I256::zero() - one_bs;
#[cfg(table_format = "q256_256")]
let neg_one_bs = I512::zero() - one_bs;
#[cfg(table_format = "q32_32")]
let neg_one_bs: i64 = -one_bs;
#[cfg(table_format = "q16_16")]
let neg_one_bs: i32 = -one_bs;
if binary_val == neg_one_bs {
let storage_tier = self.profile_max_binary_tier();
let pi_half = pi_half_at_compute_tier();
return Ok(StackValue::BinaryCompute(storage_tier, -pi_half, CompactShadow::None));
}
let value = self.to_binary_value(&value)?;
let one = self.make_int_like(&value, 1);
let x_sq = self.multiply_values(value.clone(), value.clone())?;
let one_minus_x_sq = self.subtract_values(one, x_sq)?;
let sqrt_val = self.evaluate_sqrt(one_minus_x_sq)?;
let ratio = self.binary_divide(value, sqrt_val)?;
self.evaluate_atan(ratio)
}
pub(crate) fn evaluate_acos(&mut self, value: StackValue) -> Result<StackValue, OverflowDetected> {
let asin_val = self.evaluate_asin(value)?;
let storage_tier = self.profile_max_binary_tier();
let pi_half_val = match &asin_val {
StackValue::DecimalCompute(..) => {
use crate::fixed_point::domains::decimal_fixed::transcendental::{
pi_at_decimal_compute, decimal_compute_halve,
};
let pi = pi_at_decimal_compute()?;
StackValue::DecimalCompute(storage_tier, decimal_compute_halve(pi), CompactShadow::None)
}
_ => {
let pi_half_compute = pi_half_at_compute_tier();
StackValue::BinaryCompute(storage_tier, pi_half_compute, CompactShadow::None)
}
};
self.subtract_values(pi_half_val, asin_val)
}
pub(crate) fn evaluate_atan(&mut self, value: StackValue) -> Result<StackValue, OverflowDetected> {
let storage_tier = self.profile_max_binary_tier();
if let Some(dec_compute) = self.try_decimal_compute(&value) {
use crate::fixed_point::domains::decimal_fixed::transcendental::decimal_atan;
let result = decimal_atan(dec_compute)?;
return Ok(StackValue::DecimalCompute(storage_tier, result, CompactShadow::None));
}
let compute_val = self.to_compute_storage(&value)?;
let result = atan_at_compute_tier(compute_val);
Ok(StackValue::BinaryCompute(storage_tier, result, CompactShadow::None))
}
pub(crate) fn evaluate_atan2(&mut self, y: StackValue, x: StackValue) -> Result<StackValue, OverflowDetected> {
let storage_tier = self.profile_max_binary_tier();
if let (Some(y_dec), Some(x_dec)) = (self.try_decimal_compute(&y), self.try_decimal_compute(&x)) {
use crate::fixed_point::domains::decimal_fixed::transcendental::decimal_atan2;
let result = decimal_atan2(y_dec, x_dec)?;
return Ok(StackValue::DecimalCompute(storage_tier, result, CompactShadow::None));
}
let y_compute = self.to_compute_storage(&y)?;
let x_compute = self.to_compute_storage(&x)?;
let result = atan2_at_compute_tier(y_compute, x_compute);
Ok(StackValue::BinaryCompute(storage_tier, result, CompactShadow::None))
}
pub(crate) fn to_compute_storage(&self, value: &StackValue) -> Result<ComputeStorage, OverflowDetected> {
match value {
StackValue::BinaryCompute(_, val, _) => Ok(*val),
StackValue::Binary(_, val, _) => Ok(upscale_to_compute(*val)),
StackValue::Decimal(decimals, scaled, _) => {
decimal_to_compute_storage(*decimals, *scaled)
}
StackValue::DecimalCompute(_tier, val, _) => {
use crate::fixed_point::domains::decimal_fixed::transcendental::DECIMAL_COMPUTE_DP;
#[cfg(table_format = "q64_64")]
{
let num = I512::from_i256(*val) << 128usize;
let mut den = I512::from_i128(1);
let ten = I512::from_i128(10);
for _ in 0..DECIMAL_COMPUTE_DP { den = den * ten; }
Ok((num / den).as_i256())
}
#[cfg(table_format = "q128_128")]
{
let num = I1024::from_i512(*val) << 256usize;
let mut den = I1024::from_i128(1);
let ten = I1024::from_i128(10);
for _ in 0..DECIMAL_COMPUTE_DP { den = den * ten; }
Ok((num / den).as_i512())
}
#[cfg(table_format = "q256_256")]
{
use crate::fixed_point::I2048;
use crate::fixed_point::domains::binary_fixed::i2048::i2048_div;
let num = I2048::from_i1024(*val) << 512usize;
let mut pow = I1024::from_i128(1);
let ten = I1024::from_i128(10);
for _ in 0..DECIMAL_COMPUTE_DP { pow = pow * ten; }
let den = I2048::from_i1024(pow);
let quot = i2048_div(num, den);
Ok(I1024::from_words([
quot.words[0], quot.words[1], quot.words[2], quot.words[3],
quot.words[4], quot.words[5], quot.words[6], quot.words[7],
quot.words[8], quot.words[9], quot.words[10], quot.words[11],
quot.words[12], quot.words[13], quot.words[14], quot.words[15],
]))
}
#[cfg(table_format = "q32_32")]
{
let num = I256::from_i128(*val) << 64usize;
let mut den = I256::from_i128(1);
let ten = I256::from_i128(10);
for _ in 0..DECIMAL_COMPUTE_DP { den = den * ten; }
Ok((num / den).as_i128())
}
#[cfg(table_format = "q16_16")]
{
use crate::fixed_point::frac_config;
let num = (*val as i128) << (frac_config::COMPUTE_FRAC_BITS as usize);
let mut den: i128 = 1;
for _ in 0..DECIMAL_COMPUTE_DP { den *= 10; }
Ok((num / den) as i64)
}
}
StackValue::Symbolic(rational) => {
if let (Some(num), Some(den)) = (rational.numerator_i128(), rational.denominator_i128()) {
return symbolic_to_compute_storage(num, den);
}
return symbolic_wide_to_compute_storage(rational);
}
StackValue::Ternary(tier, value, _) => {
let rational = ternary_to_rational(*tier, value)?;
if let (Some(num), Some(den)) = (rational.numerator_i128(), rational.denominator_i128()) {
symbolic_to_compute_storage(num, den)
} else {
symbolic_wide_to_compute_storage(&rational)
}
}
StackValue::Error(e) => Err(e.clone()),
}
}
pub(crate) fn to_binary_storage(&self, value: &StackValue) -> Result<BinaryStorage, OverflowDetected> {
match value {
StackValue::Binary(_, val, _) => Ok(*val),
StackValue::BinaryCompute(_, val, _) => downscale_to_storage(*val),
StackValue::DecimalCompute(_tier, val, _shadow) => {
crate::fixed_point::universal::fasc::stack_evaluator::decimal_compute_to_binary_storage_pub(*val)
}
StackValue::Decimal(decimals, scaled, _) => {
#[cfg(table_format = "q256_256")]
{
use crate::fixed_point::I1024;
let ten_pow = pow10_i512(*decimals);
let scaled_i1024 = I1024::from_i512(*scaled) << 256;
Ok((scaled_i1024 / I1024::from_i512(ten_pow)).as_i512())
}
#[cfg(table_format = "q128_128")]
{
let ten_pow = pow10_i256(*decimals);
let num = I512::from_i256(*scaled) << 128;
let den = I512::from_i256(ten_pow);
Ok((num / den).as_i256())
}
#[cfg(table_format = "q64_64")]
{
let ten_pow = pow10_i256(*decimals);
let num = I256::from_i128(*scaled) << 64;
Ok((num / ten_pow).as_i128())
}
#[cfg(table_format = "q32_32")]
{
let ten_pow = pow10_i256(*decimals);
let num = I256::from_i128(*scaled as i128) << 32;
Ok((num / ten_pow).as_i128() as i64)
}
#[cfg(table_format = "q16_16")]
{
use crate::fixed_point::frac_config;
let ten_pow = pow10_i256(*decimals);
let num = I256::from_i128(*scaled as i128) << (frac_config::FRAC_BITS as usize);
let half = ten_pow >> 1;
let rounded = if num >= I256::zero() { num + half } else { num - half };
Ok((rounded / ten_pow).as_i128() as i32)
}
}
StackValue::Symbolic(rational) => {
if let (Some(num), Some(den)) = (rational.numerator_i128(), rational.denominator_i128()) {
#[cfg(table_format = "q256_256")]
{
use crate::fixed_point::I1024;
let num_i1024 = I1024::from_i512(I512::from_i256(I256::from_i128(num))) << 256;
let den_i512 = I512::from_i256(I256::from_i128(den));
return Ok((num_i1024 / I1024::from_i512(den_i512)).as_i512());
}
#[cfg(table_format = "q128_128")]
{
return Ok((I256::from_i128(num) << 128) / I256::from_i128(den));
}
#[cfg(table_format = "q64_64")]
{
return Ok((num << 64) / den);
}
#[cfg(table_format = "q32_32")]
{
return Ok(((num << 32) / den) as i64);
}
#[cfg(table_format = "q16_16")]
{
use crate::fixed_point::frac_config;
return Ok(((num << frac_config::FRAC_BITS) / den) as i32);
}
}
let cs = symbolic_wide_to_compute_storage(rational)?;
downscale_to_storage(cs)
}
StackValue::Ternary(tier, value, _) => {
let rational = ternary_to_rational(*tier, value)?;
if let (Some(num), Some(den)) = (rational.numerator_i128(), rational.denominator_i128()) {
#[cfg(table_format = "q256_256")]
{
use crate::fixed_point::I1024;
let num_i1024 = I1024::from_i512(I512::from_i256(I256::from_i128(num))) << 256;
let den_i512 = I512::from_i256(I256::from_i128(den));
return Ok((num_i1024 / I1024::from_i512(den_i512)).as_i512());
}
#[cfg(table_format = "q128_128")]
{
return Ok((I256::from_i128(num) << 128) / I256::from_i128(den));
}
#[cfg(table_format = "q64_64")]
{
return Ok((num << 64) / den);
}
#[cfg(table_format = "q32_32")]
{
return Ok(((num << 32) / den) as i64);
}
#[cfg(table_format = "q16_16")]
{
use crate::fixed_point::frac_config;
return Ok(((num << frac_config::FRAC_BITS) / den) as i32);
}
} else {
let cs = symbolic_wide_to_compute_storage(&rational)?;
downscale_to_storage(cs)
}
}
StackValue::Error(e) => Err(*e),
}
}
pub(crate) fn parse_literal_with_mode(&mut self, s: &str) -> Result<StackValue, OverflowDetected> {
use crate::fixed_point::universal::fasc::mode::{ComputeMode, get_mode};
let mode = get_mode();
match mode.compute {
ComputeMode::Auto => self.parse_literal(s),
ComputeMode::Binary => self.parse_as_binary(s),
ComputeMode::Decimal => self.parse_as_decimal(s),
ComputeMode::Symbolic => self.parse_as_symbolic(s),
ComputeMode::Ternary => self.parse_as_ternary(s),
}
}
pub(crate) fn parse_as_binary(&mut self, s: &str) -> Result<StackValue, OverflowDetected> {
let value = self.parse_literal(s)?;
self.convert_to_binary(value)
}
pub(crate) fn parse_as_decimal(&mut self, s: &str) -> Result<StackValue, OverflowDetected> {
let value = self.parse_literal(s)?;
self.convert_to_decimal(value)
}
pub(crate) fn parse_as_symbolic(&mut self, s: &str) -> Result<StackValue, OverflowDetected> {
let value = self.parse_literal(s)?;
self.convert_to_symbolic(value)
}
pub(crate) fn parse_as_ternary(&mut self, s: &str) -> Result<StackValue, OverflowDetected> {
let value = self.parse_literal(s)?;
self.convert_to_ternary(value)
}
pub(crate) fn convert_to_binary(&self, value: StackValue) -> Result<StackValue, OverflowDetected> {
match &value {
StackValue::Binary(_, _, _) => Ok(value),
StackValue::BinaryCompute(_, _, _) => self.materialize_compute(value),
_ => {
let storage = self.to_binary_storage(&value)?;
let tier = self.profile_max_binary_tier();
let shadow = value.shadow();
Ok(StackValue::Binary(tier, storage, shadow))
}
}
}
pub(crate) fn convert_to_decimal(&self, value: StackValue) -> Result<StackValue, OverflowDetected> {
match &value {
StackValue::Decimal(_, _, _) => Ok(value),
_ => {
let rational = value.to_rational()?;
let (decimals, scaled) = rational_to_decimal_components(&rational)?;
let shadow = value.shadow();
Ok(StackValue::Decimal(decimals, to_binary_storage(scaled), shadow))
}
}
}
pub(crate) fn convert_to_symbolic(&self, value: StackValue) -> Result<StackValue, OverflowDetected> {
match &value {
StackValue::Symbolic(_) => Ok(value),
_ => {
let rational = value.to_rational()?;
Ok(StackValue::Symbolic(rational))
}
}
}
pub(crate) fn convert_to_ternary(&self, value: StackValue) -> Result<StackValue, OverflowDetected> {
match &value {
StackValue::Ternary(_, _, _) => Ok(value),
_ => {
let shadow = value.shadow();
let rational = value.to_rational()?;
let tier = self.profile_max_ternary_tier();
#[cfg(table_format = "q256_256")]
{
if tier == 5 {
let parts = rational.extract_native();
let (num512, den512) = parts.try_as_i512_pair()
.ok_or(OverflowDetected::Overflow)?;
if den512.is_zero() {
return Err(OverflowDetected::DivisionByZero);
}
let scale = {
let mut s = I512::from_i128(1);
let three = I512::from_i128(3);
for _ in 0..128 { s = s * three; }
s
};
let int_part = num512 / den512;
let remainder = num512 - int_part * den512;
let stored = int_part * scale + (remainder * scale) / den512;
let (t, bs) = ternary_to_storage(
&UniversalTernaryFixed::from_tier_raw(tier, TernaryRaw::Large(stored))?
);
return Ok(StackValue::Ternary(t, bs, shadow));
}
}
let num = rational.numerator_i128().ok_or(OverflowDetected::Overflow)?;
let den = rational.denominator_i128().ok_or(OverflowDetected::Overflow)?;
if den == 0 {
return Err(OverflowDetected::DivisionByZero);
}
match tier {
3 => {
let scale: i128 = 1_853_020_188_851_841;
let stored = if let Some(product) = num.checked_mul(scale) {
product / den
} else {
let quotient = num / den;
let remainder = num % den;
quotient.checked_mul(scale).ok_or(OverflowDetected::Overflow)?
+ remainder.checked_mul(scale).ok_or(OverflowDetected::Overflow)? / den
};
Ok(StackValue::Ternary(tier, to_binary_storage(stored), shadow))
}
4 => {
let scale = {
let mut s = I256::from_u8(1);
let three = I256::from_u8(3);
for _ in 0..64 { s = s * three; }
s
};
let num256 = I256::from_i128(num);
let den256 = I256::from_i128(den);
let stored = (num256 * scale) / den256;
let (t, bs) = ternary_to_storage(
&UniversalTernaryFixed::from_tier_raw(tier, TernaryRaw::Medium(stored))?
);
Ok(StackValue::Ternary(t, bs, shadow))
}
5 => {
let scale = {
let mut s = I512::from_i128(1);
let three = I512::from_i128(3);
for _ in 0..128 { s = s * three; }
s
};
let num512 = I512::from_i128(num);
let den512 = I512::from_i128(den);
let stored = (num512 * scale) / den512;
let (t, bs) = ternary_to_storage(
&UniversalTernaryFixed::from_tier_raw(tier, TernaryRaw::Large(stored))?
);
Ok(StackValue::Ternary(t, bs, shadow))
}
_ => {
let scale: i128 = 1_853_020_188_851_841;
let stored = if let Some(product) = num.checked_mul(scale) {
product / den
} else {
let quotient = num / den;
let remainder = num % den;
quotient.checked_mul(scale).ok_or(OverflowDetected::Overflow)?
+ remainder.checked_mul(scale).ok_or(OverflowDetected::Overflow)? / den
};
Ok(StackValue::Ternary(3, to_binary_storage(stored), shadow))
}
}
}
}
}
pub(crate) fn apply_output_mode(&self, value: StackValue) -> Result<StackValue, OverflowDetected> {
use crate::fixed_point::universal::fasc::mode::{OutputMode, get_mode};
let mode = get_mode();
match mode.output {
OutputMode::Auto => Ok(value),
OutputMode::Binary => self.convert_to_binary(value),
OutputMode::Decimal => self.convert_to_decimal(value),
OutputMode::Symbolic => self.convert_to_symbolic(value),
OutputMode::Ternary => self.convert_to_ternary(value),
}
}
}
pub(super) fn rational_to_decimal_components(rational: &RationalNumber) -> Result<(u8, i128), OverflowDetected> {
if let (Some(num), Some(den)) = (rational.numerator_i128(), rational.denominator_i128()) {
return rational_to_decimal_components_i128(num, den);
}
#[cfg(table_format = "q256_256")]
{
let parts = rational.extract_native();
if let Some((num, den)) = parts.try_as_i512_pair() {
return rational_to_decimal_components_i512(num, den);
}
}
Err(OverflowDetected::Overflow)
}
fn rational_to_decimal_components_i128(num: i128, den: i128) -> Result<(u8, i128), OverflowDetected> {
if den == 0 {
return Err(OverflowDetected::DivisionByZero);
}
let mut d = den.unsigned_abs() as u128;
let mut decimals: u32 = 0;
while d % 10 == 0 { d /= 10; decimals += 1; }
while d % 5 == 0 { d /= 5; decimals += 1; }
while d % 2 == 0 { d /= 2; decimals += 1; }
if d != 1 {
decimals = 19;
}
if decimals > 19 {
decimals = 19;
}
let num_wide = I256::from_i128(num);
let den_wide = I256::from_i128(den);
let ten = I256::from_i128(10);
let mut scale_wide = I256::from_i128(1);
for _ in 0..decimals { scale_wide = scale_wide * ten; }
let scaled_wide = num_wide * scale_wide / den_wide;
if scaled_wide.fits_in_i128() {
return Ok((decimals as u8, scaled_wide.as_i128()));
}
let mut dec = decimals;
while dec > 0 {
dec -= 1;
let mut s = I256::from_i128(1);
for _ in 0..dec { s = s * ten; }
let result = num_wide * s / den_wide;
if result.fits_in_i128() {
return Ok((dec as u8, result.as_i128()));
}
}
let result = num_wide / den_wide;
if result.fits_in_i128() {
Ok((0, result.as_i128()))
} else {
Err(OverflowDetected::Overflow)
}
}
#[cfg(table_format = "q256_256")]
fn rational_to_decimal_components_i512(num: I512, den: I512) -> Result<(u8, i128), OverflowDetected> {
if den.is_zero() {
return Err(OverflowDetected::DivisionByZero);
}
let decimals: u32 = 19;
let ten = I512::from_i128(10);
let mut scale = I512::from_i128(1);
for _ in 0..decimals { scale = scale * ten; }
let integer_part = num / den;
let remainder = num - integer_part * den;
let frac_scaled = (remainder * scale) / den;
let result = integer_part * scale + frac_scaled;
if result.fits_in_i128() {
return Ok((decimals as u8, result.as_i128()));
}
let mut dec = decimals;
while dec > 0 {
dec -= 1;
let mut s = I512::from_i128(1);
for _ in 0..dec { s = s * ten; }
let int_part = num / den;
let rem = num - int_part * den;
let frac = (rem * s) / den;
let r = int_part * s + frac;
if r.fits_in_i128() {
return Ok((dec as u8, r.as_i128()));
}
}
let r = num / den;
if r.fits_in_i128() {
Ok((0, r.as_i128()))
} else {
Err(OverflowDetected::Overflow)
}
}