use crate::common::consts::ONE;
use crate::common::util::round_p;
use crate::defs::Error;
use crate::defs::RoundingMode;
use crate::num::BigFloatNumber;
use crate::ops::consts::Consts;
use crate::Exponent;
use crate::Sign;
use crate::WORD_BIT_SIZE;
const ACOS_EXP_THRES: Exponent = -32;
impl BigFloatNumber {
pub fn acos(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Result<Self, Error> {
let p = round_p(p);
let cmpone = self.abs_cmp(&ONE);
if cmpone == 0 && self.is_positive() {
return Self::new2(p, Sign::Pos, self.inexact());
} else if cmpone > 0 {
return Err(Error::InvalidArgument);
}
let mut p_inc = WORD_BIT_SIZE;
let mut p_wrk = p.max(self.mantissa_max_bit_len()) + p_inc;
let mut add_p = (1 - ACOS_EXP_THRES) as usize;
let mut x = self.clone()?;
x.set_inexact(false);
loop {
let p_x = p_wrk + add_p;
x.set_precision(p_x, RoundingMode::None)?;
let mut ret = x.asin(p_x, RoundingMode::None, cc)?;
let mut pi = cc.pi_num(p_x, RoundingMode::None)?;
pi.set_exponent(pi.exponent() - 1);
let ret2 = pi.add(&ret, p_x, RoundingMode::None)?;
ret = pi.sub(&ret, p_x, RoundingMode::None)?;
let t = ret
.exponent()
.unsigned_abs()
.max(ret2.exponent().unsigned_abs()) as usize
+ 1; if add_p < t {
add_p = t;
} else {
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::common::{consts::ONE, util::random_subnormal};
use super::*;
#[test]
fn test_arccosine() {
let mut cc = Consts::new().unwrap();
let rm = RoundingMode::ToEven;
let p = 64;
let mut n1 = BigFloatNumber::from_word(4294967295, p).unwrap();
n1.set_exponent(0);
let _n2 = n1.acos(p, rm, &mut cc).unwrap();
let p = 320;
let n1 = BigFloatNumber::parse(
"F.FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2DC85F7E77EC487_e-1",
crate::Radix::Hex,
p,
RoundingMode::None,
&mut cc,
)
.unwrap();
let n2 = n1.acos(p, rm, &mut cc).unwrap();
let n3 = BigFloatNumber::parse("5.2049C1114CF98E7B6DB49CCF999F4A5E697D73E5DA6BEC6578098357460BAFFB0C25779F1C63E8D8_e-21", crate::Radix::Hex, p, RoundingMode::None, &mut cc).unwrap();
assert!(n2.cmp(&n3) == 0);
let n1 = BigFloatNumber::parse("1.921FB54442D18469898CC51701B839A200000000000000004D3C337F7C8D419EBBFC39B4BEC14AF6_e-10", crate::Radix::Hex, p, RoundingMode::None, &mut cc).unwrap();
let n2 = n1.acos(p, rm, &mut cc).unwrap();
let n3 = BigFloatNumber::parse("1.921FB54442D18467F76D0FD2BEE6B538C877D6FA13175F455EB9961B4834A04EF790AE0274E87FF6_e+0", 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 zero = BigFloatNumber::new(1).unwrap();
let mut half_pi = cc.pi_num(p, RoundingMode::ToEven).unwrap();
half_pi.set_exponent(1);
assert!(d1.acos(p, rm, &mut cc).is_err());
assert!(d2.acos(p, rm, &mut cc).is_err());
assert!(d3.acos(p, rm, &mut cc).unwrap().cmp(&half_pi) == 0);
assert!(zero.acos(p, rm, &mut cc).unwrap().cmp(&half_pi) == 0);
assert!(ONE.acos(p, rm, &mut cc).unwrap().is_zero());
let n1 = random_subnormal(p);
assert!(n1.acos(p, rm, &mut cc).unwrap().cmp(&half_pi) == 0);
}
#[ignore]
#[test]
#[cfg(feature = "std")]
fn arccosine_perf() {
let mut cc = Consts::new().unwrap();
let p = 133;
let mut n = vec![];
for _ in 0..10000 {
n.push(BigFloatNumber::random_normal(p, -5, 5).unwrap());
}
for _ in 0..5 {
let start_time = std::time::Instant::now();
for ni in n.iter() {
let _f = ni.acos(p, RoundingMode::ToEven, &mut cc).unwrap();
}
let time = start_time.elapsed();
println!("{}", time.as_millis());
}
}
}