use crate::defs::Error;
use crate::defs::DECIMAL_BASE;
use crate::defs::DECIMAL_BASE_LOG10;
use crate::defs::DECIMAL_SIGN_NEG;
use crate::defs::DECIMAL_SIGN_POS;
use crate::inc::inc::BigFloatInc;
use crate::inc::inc::DECIMAL_PARTS;
use crate::inc::ops::tables::exp_const::EXP_VALUES;
use crate::inc::ops::tables::exp_const::EXP_VALUES2;
use crate::inc::ops::tables::fact_const::INVFACT_VALUES;
impl BigFloatInc {
pub fn pow(&self, d1: &Self) -> Result<Self, Error> {
if self.n == 0 {
if d1.sign == DECIMAL_SIGN_NEG {
return Err(Error::ExponentOverflow(DECIMAL_SIGN_POS));
} else if d1.n == 0 {
return Err(Error::InvalidArgument);
} else {
return Ok(*self);
}
}
if Self::extract_fract_part(d1).n == 0 {
let mut int = Self::extract_int_part(d1);
int.sign = d1.sign;
Self::result_inversion(self.powi(&int), d1.sign == DECIMAL_SIGN_NEG, self.sign)
} else {
self.powexp(d1)
}
}
fn powexp(&self, d1: &Self) -> Result<Self, Error> {
let b = self.abs();
let x = d1.mul(&b.ln()?)?;
let one = BigFloatInc::one();
let int = Self::extract_int_part(&x);
let frac = Self::extract_fract_part(&x);
let p1 = if int.n != 0 {
Self::result_inversion(Self::expi(&int), x.sign == DECIMAL_SIGN_NEG, self.sign)?
} else {
one
};
let p2 = if frac.n != 0 { BigFloatInc::expf(&frac)? } else { one };
let ml = Self::result_inversion(p1.mul(&p2), x.sign == DECIMAL_SIGN_NEG, self.sign)?;
let mut ret = if x.sign == DECIMAL_SIGN_NEG { one.div(&ml)? } else { ml };
ret.sign = self.sign;
Ok(ret)
}
fn result_inversion(r: Result<Self, Error>, conv: bool, base_sign: i8) -> Result<Self, Error> {
match r {
Ok(v) => Ok(v),
Err(Error::ExponentOverflow(_)) => {
if conv {
Ok(Self::new())
} else {
Err(Error::ExponentOverflow(base_sign))
}
}
Err(Error::DivisionByZero) => Err(Error::ExponentOverflow(base_sign)),
Err(e) => Err(e),
}
}
fn expi(d1: &Self) -> Result<Self, Error> {
let mut int = *d1;
let mut ret = Self::one();
let mut pow_idx = 0;
while int.n > 0 {
if pow_idx > 2 {
return Err(Error::ExponentOverflow(DECIMAL_SIGN_POS));
}
let mut cnt = int.m[0] % 10;
while cnt > 0 {
ret = ret.mul(&EXP_VALUES2[pow_idx])?;
cnt -= 1;
}
pow_idx += 1;
Self::shift_right(&mut int.m, 1);
int.n -= 1;
}
Ok(ret)
}
fn powi(&self, d1: &Self) -> Result<Self, Error> {
let mut int = *d1;
let mut ret = Self::one();
let mut ml = *self;
while int.n > 0 {
if int.m[0] & 1 != 0 {
ret = ret.mul(&ml)?;
if ret.n == 0 {
break;
}
}
Self::divide_by_two_int(&mut int);
if int.n > 0 {
ml = ml.mul(&ml)?;
}
}
if d1.sign == DECIMAL_SIGN_NEG {
ret = Self::one().div(&ret)?
}
Ok(ret)
}
fn expf(d1: &Self) -> Result<Self, Error> {
let one = Self::one();
if d1.n == 0 {
return Ok(one);
}
let mut p2 = *d1;
p2.maximize_mantissa();
let mut idx = p2.m[DECIMAL_PARTS - 1];
let mut e = -(p2.e as i32);
let e_p1;
if e < 48 {
let mut t = 1;
while e >= 44 {
t *= 10;
e -= 1;
}
idx /= t;
p2.m[DECIMAL_PARTS - 1] %= t;
p2.n = Self::num_digits(&p2.m);
e_p1 = EXP_VALUES[idx as usize];
} else {
e_p1 = one;
}
let mut ret = one.add(&p2)?;
let mut ml = p2;
for i in 1..INVFACT_VALUES.len() {
ml = ml.mul(&p2)?;
let val = ret.add(&ml.mul(&INVFACT_VALUES[i])?)?;
if val.cmp(&ret) == 0 {
break;
}
ret = val;
}
ret.mul(&e_p1)
}
fn divide_by_two_int(d1: &mut Self) {
if d1.m[0] & 1 == 1 && d1.e > 0 {
d1.maximize_mantissa();
}
d1.m[0] >>= 1;
for i in 1..(d1.n as usize + DECIMAL_BASE_LOG10 - 1) / DECIMAL_BASE_LOG10 {
if d1.m[i] & 1 != 0 {
d1.m[i - 1] += DECIMAL_BASE as i16 / 2;
}
d1.m[i] >>= 1;
}
d1.n = Self::num_digits(&d1.m);
}
}