use crate::common::consts::ONE;
use crate::common::util::count_leading_zeroes_skip_first;
use crate::common::util::round_p;
use crate::defs::Error;
use crate::defs::RoundingMode;
use crate::num::BigFloatNumber;
use crate::Consts;
use crate::Sign;
use crate::EXPONENT_MAX;
use crate::WORD_BIT_SIZE;
impl BigFloatNumber {
pub fn acosh(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Result<Self, Error> {
let p = round_p(p);
let cmpone = self.cmp(&ONE);
if cmpone == 0 {
return Self::new2(p, Sign::Pos, self.inexact());
} else if cmpone < 0 {
return Err(Error::InvalidArgument);
}
let p_max = p.max(self.mantissa_max_bit_len());
let mut x = self.clone()?;
x.set_inexact(false);
let mut p_inc = WORD_BIT_SIZE;
let mut p_wrk = p_max + p_inc;
loop {
let mut p_x = p_wrk;
let mut ret = if (self.exponent() as isize - 1) / 2 > p_x as isize + 2 {
if self.exponent() == EXPONENT_MAX {
p_x += 2;
let lnx = x.ln(p_x, RoundingMode::None, cc)?;
let ln2 = cc.ln_2_num(p_x, RoundingMode::None)?;
ln2.add(&lnx, p_x, RoundingMode::None)?
} else {
x.set_exponent(self.exponent() + 1);
let lnx = x.ln(p_x, RoundingMode::None, cc)?;
x.set_exponent(self.exponent());
lnx
}
} else {
let mut additional_prec = 0;
if self.exponent() == 1 {
additional_prec = count_leading_zeroes_skip_first(self.mantissa().digits());
}
p_x += 6 + additional_prec;
let xx = x.mul(&x, p_x, RoundingMode::None)?;
let d1 = xx.sub(&ONE, p_x, RoundingMode::None)?;
let d2 = d1.sqrt(p_x, RoundingMode::None)?;
let d3 = d2.add(&x, p_x, RoundingMode::FromZero)?;
d3.ln(p_x, RoundingMode::None, cc)?
};
if ret.try_set_precision(p, rm, p_wrk)? {
ret.set_inexact(ret.inexact() | self.inexact());
return Ok(ret);
}
p_wrk += p_inc;
p_inc = round_p(p_wrk / 5);
}
}
}
#[cfg(test)]
mod tests {
use crate::Exponent;
use super::*;
#[test]
fn test_acosh() {
let mut cc = Consts::new().unwrap();
let rm = RoundingMode::ToEven;
let p = 448;
let n1 = BigFloatNumber::parse("1.0000000000000000000000000000000000000000000B56A0EBA6F7D47E21A7B2A7806A698BABAF2F05BC61E2F8FB50FE0B98F55B181AC9C8_e+0", crate::Radix::Hex, p, RoundingMode::None, &mut cc).unwrap();
let n2 = n1.acosh(p, rm, &mut cc).unwrap();
let n3 = BigFloatNumber::parse("4.C31368910963B1A1BCFC0EDBD393FB7A5E876F9751D93A20E7E48EC0D16090ADA5F46DF2184D32A19C500088EA09CBD4F23DF713113D8A58_e-16", crate::Radix::Hex, p, RoundingMode::None, &mut cc).unwrap();
assert!(n2.cmp(&n3) == 0);
let p = 320;
let n1 = BigFloatNumber::parse("1.921FB54442D18469898CC51701B839A200000000000000004D3C337F7C8D419EBBFC39B4BEC14AF6_e+1000", crate::Radix::Hex, p, RoundingMode::None, &mut cc).unwrap();
let n2 = n1.acosh(p, rm, &mut cc).unwrap();
let n3 = BigFloatNumber::parse("2.C5DAB0AF9025886C3364C7B6D6741EB19D4FB009D3F92CA21B77498D9F0666363C665F2F324EAEC8_e+3", crate::Radix::Hex, p, RoundingMode::None, &mut cc).unwrap();
assert!(n2.cmp(&n3) == 0);
let d1 = BigFloatNumber::max_value(p).unwrap();
let d2 = BigFloatNumber::min_value(p).unwrap();
let d3 = BigFloatNumber::min_positive(p).unwrap();
let mut d4 = d1.acosh(p, RoundingMode::Down, &mut cc).unwrap();
d4.set_exponent(d4.exponent() - 1);
let d5 = d4.cosh(p, rm, &mut cc).unwrap();
let mut d5 = d5.mul(&d5, p, rm).unwrap();
d5.set_exponent(d5.exponent() + 1);
let mut eps = ONE.clone().unwrap();
eps.set_exponent(
d1.exponent() - p as Exponent + core::mem::size_of::<Exponent>() as Exponent * 8,
);
assert!(
d1.sub(&d5, p, RoundingMode::ToEven)
.unwrap()
.abs()
.unwrap()
.cmp(&eps)
< 0
);
assert!(d2.acosh(p, rm, &mut cc).unwrap_err() == Error::InvalidArgument);
assert!(d3.acosh(p, rm, &mut cc).unwrap_err() == Error::InvalidArgument);
assert!(ONE.acosh(p, rm, &mut cc).unwrap().is_zero());
}
#[ignore]
#[test]
#[cfg(feature = "std")]
fn acosh_perf() {
let mut cc = Consts::new().unwrap();
let mut n = vec![];
let p = 160;
for _ in 0..10000 {
n.push(BigFloatNumber::random_normal(p, 0, 5).unwrap());
}
for _ in 0..5 {
let start_time = std::time::Instant::now();
for ni in n.iter() {
let _f = ni.acosh(p, RoundingMode::ToEven, &mut cc).unwrap();
}
let time = start_time.elapsed();
println!("{}", time.as_millis());
}
}
}