use crate::InnerFloat::{Finite, Infinity, NaN, Zero};
use crate::float::arithmetic::round_near_x::{
LEADING_TERM_MIN_EXPONENT, round_rational_leading_term, small_input_shortcut,
};
use crate::float::arithmetic::sin::{
SCALE, SCALED_INPUT_EXPONENT, UNDERFLOW_EXPONENT, scaled_underflow, underflowed,
};
use crate::float::arithmetic::tan::round_bracket_signed_by;
use crate::{Float, emulate_float_to_float_fn, emulate_rational_to_float_fn};
use alloc::vec;
use core::cmp::Ordering::{self, Equal, Greater};
use core::mem::take;
use malachite_base::num::arithmetic::traits::{
Abs, Atan, AtanAssign, CeilingLogBase2, IsPowerOf2, Parity, PowerOf2, Reciprocal, Square,
SquareAssign,
};
use malachite_base::num::basic::floats::PrimitiveFloat;
use malachite_base::num::basic::integers::PrimitiveInt;
use malachite_base::num::basic::traits::{
NaN as NaNTrait, NegativeZero as NegativeZeroTrait, One, Zero as ZeroTrait,
};
use malachite_base::num::conversion::traits::{ExactFrom, RoundingFrom};
use malachite_base::num::logic::traits::SignificantBits;
use malachite_base::rounding_modes::RoundingMode::{self, *};
use malachite_base::split_into_chunks_mut;
use malachite_nz::integer::Integer;
use malachite_nz::natural::Natural;
use malachite_nz::natural::arithmetic::float::round::float_can_round;
use malachite_nz::platform::Limb;
use malachite_q::Rational;
const ATAN_TABLE: [[u64; 3]; 20] = [
[0x6e141587261cdf00, 0x6fe445ecbc3a8d03, 0xed63382b0dda7b45], [0xaa7fa90388b3836b, 0x6dc79ef5f7a217e5, 0xfadbafc96406eb15], [0x319c12cf59d4b2dc, 0xcb2792dc0e2e0d51, 0xffaaddb967ef4e36], [0x8b3957d95d9ad922, 0xc897989f3e888ef7, 0xfeadd4d5617b6e32], [0xc4e6abc8af62e439, 0x4eb9bf602625f0b4, 0xfd0fcdd343cac19b], [0x7c18baeb9bc95789, 0xb12afb6b6d4f7e16, 0xffffaaaaddddb94b], [0x6856a0171a2f001a, 0x62351fbbe60af47, 0xfffeaaadddd4b968], [0x69164c094f49da06, 0xd517294f7373d07a, 0xfffd001032cb1179], [0x20ef65c10deef460, 0xe78c564015f76048, 0xfffaaadddb94d5bb], [0x3ce233aa002f0344, 0x9dd8ea342a65d4cc, 0xfff7ab27a1f32f95], [0xa37f403c7279c5cb, 0x13ab53a1c8db8497, 0xfff40103192ce74d], [0xe5a85657103c1aa8, 0xb8409e6c914191d3, 0xffefac8a9c40a26b], [0x806d0294c0db8816, 0x779d776dda8c6213, 0xffeaaddd4bb12542], [0x5545d1914ef21478, 0x3aea58d6660f5a12, 0xffe5051f0aebf73a], [0x6e47a91d015f4133, 0xc085ab6b490b7f02, 0xffdeb2787d4adac1], [0x4efc1f931f7ec9b3, 0xb7f43cd16195ef4b, 0xffd7b61702b09aad], [0xd27d1dbf55fed60d, 0xd812c11d7d473e5e, 0xffd0102cb3c1bfbe], [0xca629e927383fe97, 0x8c61aedf58e42206, 0xffc7c0f05db9d1b6], [0x4eff0b53d4e905b7, 0x28ac1e800ca31e9d, 0xffbec89d7dddd7e9], [0xb0a7931deec6fe60, 0xb46feea78588554b, 0xffb527743c8cdd8f], ];
fn set_table(prec: u64, x: &[u64; 3]) -> Float {
let n = (Natural::from(x[2]) << 128u32) | (Natural::from(x[1]) << 64u32) | Natural::from(x[0]);
Float::from_rational_prec_round(Rational::from(n) >> 192u32, prec, Down).0
}
fn mul_prev(xs: &mut [Integer], k: usize) {
let (lo, hi) = xs.split_at_mut(k);
lo[k - 1] *= &hi[0];
}
fn atan_aux(mut p: Integer, mut r: u64, m: usize, precy: u64) -> Float {
debug_assert!(p > 0u32);
debug_assert!(m > 0);
if precy <= 192 {
let index = match r {
1 => Some(0),
2 => Some(1),
4 => Some(1 + usize::exact_from(&p)),
8 => Some(4 + usize::exact_from(&p)),
_ => None,
};
if let Some(index) = index {
return set_table(precy, &ATAN_TABLE[index]);
}
}
p.square_assign();
r <<= 1;
let n = p.trailing_zeros().unwrap();
if n > 0 {
p >>= n;
r -= n;
}
debug_assert!(r > 0);
let len = m + 2;
let mut scratch = vec![Integer::ZERO; (len << 1) + m + 1];
split_into_chunks_mut!(scratch, len, [s, q], ptoj);
let mut log2_nb_terms = vec![0u64; len + 1];
let mut accu = vec![0i64; len + 1];
let ri = i64::exact_from(r);
let mut i = 0u64;
let mut k = 0usize;
let p_is_1 = p == 1u32;
if p_is_1 {
let mut n = u64::power_of_2(u64::exact_from(m));
if precy / r <= n {
n = precy / r + 1;
}
while i < n {
q[k + 1] = Integer::from((i << 1) + 3);
s[k] = (&q[k + 1] << r) - Integer::from((i << 1) + 1);
q[k] = &q[k + 1] * Integer::from((i << 1) + 1);
log2_nb_terms[k] = 1; let mut j = (i + 2) >> 1;
let mut l = 1u64;
while j.even() {
debug_assert!(k > 0);
s[k] *= &q[k - 1];
let mut t = &s[k - 1] * &q[k];
t <<= r << l;
t += &s[k];
s[k - 1] = t;
mul_prev(q, k);
log2_nb_terms[k - 1] = l + 1;
l += 1;
j >>= 1;
k -= 1;
}
i += 2;
k += 1;
}
} else {
ptoj[0] = p.clone();
for im in 1..=m {
ptoj[im] = (&ptoj[im - 1]).square();
}
let n = u64::power_of_2(u64::exact_from(m));
let mut done = false;
while i < n && !done {
q[k + 1] = Integer::from((i << 1) + 3); s[k + 1] = &p * Integer::from((i << 1) + 1); s[k] = (&q[k + 1] << r) - &s[k + 1]; q[k] = &q[k + 1] * Integer::from((i << 1) + 1); log2_nb_terms[k] = 1; let mut j = (i + 2) >> 1;
let mut l = 1u64;
while j.even() {
debug_assert!(k > 0);
s[k] *= &q[k - 1];
s[k] *= &ptoj[usize::exact_from(l)];
let mut t = &s[k - 1] * &q[k];
t <<= r << l;
t += &s[k];
s[k - 1] = t;
mul_prev(q, k);
log2_nb_terms[k - 1] = l + 1;
let mult = (ri << (l + 1))
- i64::exact_from(ptoj[usize::exact_from(l + 1)].significant_bits())
- 1;
accu[k - 1] = if k == 1 { mult } else { accu[k - 2] + mult };
if accu[k - 1] > i64::exact_from(precy) {
done = true;
}
l += 1;
j >>= 1;
k -= 1;
}
i += 2;
k += 1;
}
}
let mut h = 0u64; while k > 1 {
k -= 1;
s[k] *= &q[k - 1];
if !p_is_1 {
s[k] *= &ptoj[usize::exact_from(log2_nb_terms[k - 1])];
}
let mut t = &s[k - 1] * &q[k];
h += u64::power_of_2(log2_nb_terms[k]);
t <<= r * h;
t += &s[k];
s[k - 1] = t;
mul_prev(q, k);
}
let mut s0 = take(&mut s[0]);
let mut q0 = take(&mut q[0]);
let precy_i = i64::exact_from(precy);
let mut diff = i64::exact_from(s0.significant_bits()) - (precy_i << 1);
let mut expo = diff;
s0 >>= diff;
diff = i64::exact_from(q0.significant_bits()) - precy_i;
expo -= diff;
q0 >>= diff;
s0 /= q0; Float::from_rational_prec_round(
Rational::from(s0) << (expo - ri * (i64::exact_from(i) - 1)),
precy,
Floor,
)
.0
}
pub(crate) fn alternating_odd_series<F: Fn(u64) -> Option<Rational>>(
x: &Rational,
prec: u64,
rm: RoundingMode,
ratio: F,
) -> (Float, Ordering) {
let negative = *x < 0u32;
let ax = x.abs();
let x2 = (&ax).square();
let mut power = ax.clone();
let mut coefficient = Rational::ONE;
let mut hi = ax;
let mut lo = Rational::ZERO;
let mut k = 1u64;
loop {
power *= &x2;
if let Some(r) = ratio(k) {
coefficient *= r;
}
let t = &coefficient * &power / Rational::from((k << 1) + 1);
if k.odd() {
lo = &hi - t;
} else {
hi = &lo + t;
}
if let Some(result) = round_bracket_signed_by(negative, lo.clone(), hi.clone(), prec, rm) {
return result;
}
k += 1;
}
}
fn atan_series(x: &Rational, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
alternating_odd_series(x, prec, rm, |_| None)
}
fn atan_huge_step(
negative: bool,
lo: &Rational,
hi: &Rational,
w: u64,
prec: u64,
rm: RoundingMode,
) -> Option<(Float, Ordering)> {
let pi_lo = Rational::exact_from(&Float::pi_prec_round(w, Floor).0);
let pi_hi = &pi_lo + Rational::power_of_2(2 - i64::exact_from(w));
round_bracket_signed_by(
negative,
(pi_lo >> 1u32) - hi,
(pi_hi >> 1u32) - lo,
prec,
rm,
)
}
fn atan_rational_huge(x: &Rational, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
let negative = *x < 0u32;
let t = x.abs().reciprocal();
let mut lo = Rational::ZERO;
let mut hi = t.clone();
let mut w = prec + 64;
if let Some(result) = atan_huge_step(negative, &lo, &hi, w, prec, rm) {
return result;
}
let t2 = (&t).square();
let mut term = t;
let mut k = 1u64;
loop {
w <<= 1;
term *= &t2;
let d = &term / Rational::from((k << 1) + 1);
if k.odd() {
lo = &hi - d;
} else {
hi = &lo + d;
}
if let Some(result) = atan_huge_step(negative, &lo, &hi, w, prec, rm) {
return result;
}
k += 1;
}
}
pub(crate) fn atan_rational_helper(x: &Rational, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
assert_ne!(rm, Exact, "Inexact atan");
let exp_x = x.floor_log_base_2_abs() + 1; if exp_x < UNDERFLOW_EXPONENT {
return underflowed(*x > 0u32, prec, rm);
}
if exp_x > LEADING_TERM_MIN_EXPONENT
&& -(exp_x << 1) > i64::exact_from(prec + x.denominator_ref().significant_bits()) + 4
{
return round_rational_leading_term(x.abs(), *x > 0u32, false, prec, rm);
}
if exp_x < 0 && -(exp_x << 2) > i64::exact_from(prec) + 3 {
return atan_series(x, prec, rm);
}
if exp_x > Float::MAX_EXPONENT_I64 {
return atan_rational_huge(x, prec, rm);
}
let mut m = prec + prec.ceiling_log_base_2() + 8;
let mut increment = Limb::WIDTH;
loop {
let (f, o_f) = Float::from_rational_prec_ref(x, m);
if o_f == Equal {
return atan_prec_round_normal_ref(&f, prec, rm);
}
let a = (&f).atan();
if float_can_round(a.significand_ref().unwrap(), m - 2, prec, rm) {
return Float::from_float_prec_round(a, prec, rm);
}
m += increment;
increment = m >> 1;
}
}
fn atan_prec_round_normal_ref(x: &Float, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
assert_ne!(rm, Exact, "Inexact atan");
let exp_x = i64::from(x.get_exponent().unwrap());
if let Some(result) = small_input_shortcut(x, -(exp_x << 1), 1, false, prec, rm) {
return result;
}
let negative = *x < 0u32;
let xp = x.clone().abs();
let comparison = xp.partial_cmp(&1u32).unwrap();
if comparison == Equal {
let (pi, o) = Float::pi_prec_round(prec, if negative { -rm } else { rm });
let quarter = pi >> 2u32;
return if negative {
(-quarter, o.reverse())
} else {
(quarter, o)
};
}
let mut realprec = prec + prec.ceiling_log_base_2() + 4;
let mut increment = Limb::WIDTH;
let sup = if exp_x < 0 {
u64::exact_from(2 - exp_x)
} else {
1
};
loop {
let n0 = (realprec + sup + 3).ceiling_log_base_2();
let mut wp = realprec + sup + 1 + (3 * n0 - 2).ceiling_log_base_2();
let (log2p, est_lost) = if prec > 100 {
let log2p = (wp.ceiling_log_base_2() >> 1) - 3;
(log2p, 9 + (log2p << 1))
} else {
(0, 0)
};
wp += est_lost;
let mut sk = if comparison == Greater {
xp.reciprocal_prec_ref(wp).0
} else {
Float::from_float_prec_ref(&xp, wp).0
};
let mut lost = 0u64;
let mut red = 0u64;
let log2p_i = i64::exact_from(log2p);
loop {
let exp_sk = i64::from(sk.get_exponent().unwrap());
if exp_sk <= -log2p_i {
break;
}
lost = u64::exact_from(9 - (exp_sk << 1));
let mut tmp = sk.square_prec_ref(wp).0;
tmp.add_prec_assign_ref(&Float::ONE, wp);
tmp.sqrt_prec_assign(wp);
tmp.sub_prec_assign_ref(&Float::ONE, wp);
sk = if red == 0 && comparison == Greater {
tmp.mul_prec_val_ref(&xp, wp).0
} else {
tmp.div_prec_val_ref(&sk, wp).0
};
red += 1;
}
debug_assert!(sk < 1u32);
let mut arctgt = Float::ZERO;
let mut twopoweri = 1u64;
for i in 0..n0 {
if sk == 0u32 {
break;
}
let ukz = Integer::rounding_from(&(&sk << twopoweri), Down).0;
if ukz != 0u32 {
let tmp = Float::from_integer_prec_ref(&ukz, wp).0 >> twopoweri;
let tmp2 = atan_aux(ukz, twopoweri, usize::exact_from(n0 - i), wp)
.mul_prec_val_ref(&tmp, wp)
.0;
arctgt.add_prec_assign(tmp2, wp);
let tmp2 = sk.sub_prec_ref_ref(&tmp, wp).0;
sk.mul_prec_assign_ref(&tmp, wp);
sk.add_prec_assign_ref(&Float::ONE, wp);
sk = tmp2.div_prec(sk, wp).0;
}
twopoweri <<= 1;
}
arctgt.add_prec_assign(sk, wp);
arctgt <<= red;
if comparison == Greater {
arctgt = (Float::pi_prec(wp).0 >> 1u32).sub_prec(arctgt, wp).0;
}
debug_assert!(arctgt > 0u32);
let err = i64::exact_from(realprec + est_lost) - i64::exact_from(lost);
if err > 0
&& float_can_round(
arctgt.significand_ref().unwrap(),
u64::exact_from(err),
prec,
rm,
)
{
return Float::from_float_prec_round(if negative { -arctgt } else { arctgt }, prec, rm);
}
realprec += increment;
increment = realprec >> 1;
}
}
pub(crate) fn scaled_unsigned(
u: u64,
k: u32,
positive: bool,
prec: u64,
rm: RoundingMode,
) -> (Float, Ordering) {
let (f, o) = Float::from_unsigned_prec_round(u, prec, if positive { rm } else { -rm });
let f = f >> k;
if positive { (f, o) } else { (-f, o.reverse()) }
}
fn atan_with_period_prec_round_normal_ref(
x: &Float,
u: u64,
prec: u64,
rm: RoundingMode,
) -> (Float, Ordering) {
let positive = *x > 0u32;
let exp_x = i64::from(x.get_exponent().unwrap());
if exp_x == 1 && x.significand_ref().unwrap().is_power_of_2() {
return scaled_unsigned(u, 3, positive, prec, rm);
}
assert_ne!(rm, Exact, "Inexact atan_with_period");
if exp_x >= 65 && exp_x > i64::exact_from(prec) + 2 {
let w = if prec <= 63 { 65 } else { prec + 2 };
let mut t = Float::from_unsigned_prec_round(u, w, Exact).0;
t.decrement();
t >>= 2u32;
return Float::from_float_prec_round(if positive { t } else { -t }, prec, rm);
}
arc_with_period_scale(
|w| x.atan_prec_round_ref(w, Up).0 << SCALE,
u,
positive,
prec,
rm,
)
}
pub(crate) fn arc_with_period_scale<F: FnMut(u64) -> Float>(
mut scaled_f: F,
u: u64,
positive: bool,
prec: u64,
rm: RoundingMode,
) -> (Float, Ordering) {
let mut w = prec + prec.ceiling_log_base_2() + 10;
let mut increment = Limb::WIDTH;
let u_float = Float::from(u);
loop {
let mut t = scaled_f(w);
t.mul_prec_round_assign_ref(&u_float, w, Up);
let two_pi = Float::pi_prec_round(w, Down).0 << 1u32;
t.div_prec_round_assign(two_pi, w, Up);
if let Some(result) = scaled_underflow(&t, positive, prec, rm) {
return result;
}
let t = t >> SCALE;
if float_can_round(t.significand_ref().unwrap(), w - 4, prec, rm) {
return Float::from_float_prec_round(t, prec, rm);
}
w += increment;
increment = w >> 1;
}
}
pub(crate) fn atan_with_period_rational_helper(
x: &Rational,
u: u64,
prec: u64,
rm: RoundingMode,
) -> (Float, Ordering) {
let positive = *x > 0u32;
let exp_x = x.floor_log_base_2_abs() + 1; if exp_x == 1 && x.denominator_ref() == &1u32 {
return scaled_unsigned(u, 3, positive, prec, rm);
}
assert_ne!(rm, Exact, "Inexact atan_with_period_rational");
if exp_x >= 65 && exp_x > i64::exact_from(prec) + 2 {
let w = if prec <= 63 { 65 } else { prec + 2 };
let mut t = Float::from_unsigned_prec_round(u, w, Exact).0;
t.decrement();
t >>= 2u32;
return Float::from_float_prec_round(if positive { t } else { -t }, prec, rm);
}
if exp_x <= SCALED_INPUT_EXPONENT {
let scaled = x << SCALE;
return arc_with_period_scale(
|w| Float::from_rational_prec_round_ref(&scaled, w, Up).0,
u,
positive,
prec,
rm,
);
}
arc_with_period_scale(
|w| atan_rational_helper(x, w, Up).0 << SCALE,
u,
positive,
prec,
rm,
)
}
impl Float {
#[inline]
pub fn atan_prec_round(self, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
self.atan_prec_round_ref(prec, rm)
}
pub fn atan_prec_round_ref(&self, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
assert_ne!(prec, 0);
match &self.0 {
NaN => (Self::NAN, Equal),
Infinity { sign } => {
assert_ne!(rm, Exact, "Inexact atan");
let (pi, o) = Self::pi_prec_round(prec, if *sign { rm } else { -rm });
let half = pi >> 1u32;
if *sign {
(half, o)
} else {
(-half, o.reverse())
}
}
Zero { .. } => (self.clone(), Equal),
Finite { .. } => atan_prec_round_normal_ref(self, prec, rm),
}
}
#[inline]
pub fn atan_prec(self, prec: u64) -> (Self, Ordering) {
self.atan_prec_round(prec, Nearest)
}
#[inline]
pub fn atan_prec_ref(&self, prec: u64) -> (Self, Ordering) {
self.atan_prec_round_ref(prec, Nearest)
}
#[inline]
pub fn atan_round(self, rm: RoundingMode) -> (Self, Ordering) {
let prec = self.significant_bits();
self.atan_prec_round(prec, rm)
}
#[inline]
pub fn atan_round_ref(&self, rm: RoundingMode) -> (Self, Ordering) {
self.atan_prec_round_ref(self.significant_bits(), rm)
}
#[inline]
pub fn atan_prec_round_assign(&mut self, prec: u64, rm: RoundingMode) -> Ordering {
let o;
(*self, o) = self.atan_prec_round_ref(prec, rm);
o
}
#[inline]
pub fn atan_prec_assign(&mut self, prec: u64) -> Ordering {
self.atan_prec_round_assign(prec, Nearest)
}
#[inline]
pub fn atan_round_assign(&mut self, rm: RoundingMode) -> Ordering {
let prec = self.significant_bits();
self.atan_prec_round_assign(prec, rm)
}
}
impl Float {
#[inline]
pub fn atan_with_period_prec_round(
self,
u: u64,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
self.atan_with_period_prec_round_ref(u, prec, rm)
}
pub fn atan_with_period_prec_round_ref(
&self,
u: u64,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
assert_ne!(prec, 0);
match &self.0 {
NaN => (Self::NAN, Equal),
Infinity { sign } => {
if u == 0 {
(
if *sign {
Self::ZERO
} else {
Self::NEGATIVE_ZERO
},
Equal,
)
} else {
scaled_unsigned(u, 2, *sign, prec, rm)
}
}
Zero { .. } => (self.clone(), Equal),
Finite { .. } => {
if u == 0 {
(
if *self < 0u32 {
Self::NEGATIVE_ZERO
} else {
Self::ZERO
},
Equal,
)
} else {
atan_with_period_prec_round_normal_ref(self, u, prec, rm)
}
}
}
}
#[inline]
pub fn atan_with_period_prec(self, u: u64, prec: u64) -> (Self, Ordering) {
self.atan_with_period_prec_round(u, prec, Nearest)
}
#[inline]
pub fn atan_with_period_prec_ref(&self, u: u64, prec: u64) -> (Self, Ordering) {
self.atan_with_period_prec_round_ref(u, prec, Nearest)
}
#[inline]
pub fn atan_with_period_round(self, u: u64, rm: RoundingMode) -> (Self, Ordering) {
let prec = self.significant_bits();
self.atan_with_period_prec_round(u, prec, rm)
}
#[inline]
pub fn atan_with_period_round_ref(&self, u: u64, rm: RoundingMode) -> (Self, Ordering) {
self.atan_with_period_prec_round_ref(u, self.significant_bits(), rm)
}
#[inline]
pub fn atan_with_period(self, u: u64) -> Self {
let prec = self.significant_bits();
self.atan_with_period_prec(u, prec).0
}
#[inline]
pub fn atan_with_period_ref(&self, u: u64) -> Self {
self.atan_with_period_prec_ref(u, self.significant_bits()).0
}
#[inline]
pub fn atan_with_period_prec_round_assign(
&mut self,
u: u64,
prec: u64,
rm: RoundingMode,
) -> Ordering {
let (t, o) = self.atan_with_period_prec_round_ref(u, prec, rm);
*self = t;
o
}
#[inline]
pub fn atan_with_period_prec_assign(&mut self, u: u64, prec: u64) -> Ordering {
self.atan_with_period_prec_round_assign(u, prec, Nearest)
}
#[inline]
pub fn atan_with_period_round_assign(&mut self, u: u64, rm: RoundingMode) -> Ordering {
let prec = self.significant_bits();
self.atan_with_period_prec_round_assign(u, prec, rm)
}
#[inline]
pub fn atan_with_period_assign(&mut self, u: u64) {
let prec = self.significant_bits();
self.atan_with_period_prec_assign(u, prec);
}
}
impl Float {
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan_rational_prec_round(x: Rational, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
Self::atan_rational_prec_round_ref(&x, prec, rm)
}
pub fn atan_rational_prec_round_ref(
x: &Rational,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
assert_ne!(prec, 0);
if *x == 0u32 {
return (Self::ZERO, Equal);
}
atan_rational_helper(x, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan_rational_prec(x: Rational, prec: u64) -> (Self, Ordering) {
Self::atan_rational_prec_round_ref(&x, prec, Nearest)
}
#[inline]
pub fn atan_rational_prec_ref(x: &Rational, prec: u64) -> (Self, Ordering) {
Self::atan_rational_prec_round_ref(x, prec, Nearest)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan_with_period_rational_prec_round(
x: Rational,
u: u64,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
Self::atan_with_period_rational_prec_round_ref(&x, u, prec, rm)
}
pub fn atan_with_period_rational_prec_round_ref(
x: &Rational,
u: u64,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
assert_ne!(prec, 0);
if *x == 0u32 || u == 0 {
return (
if *x < 0u32 {
Self::NEGATIVE_ZERO
} else {
Self::ZERO
},
Equal,
);
}
atan_with_period_rational_helper(x, u, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan_with_period_rational_prec(x: Rational, u: u64, prec: u64) -> (Self, Ordering) {
Self::atan_with_period_rational_prec_round_ref(&x, u, prec, Nearest)
}
#[inline]
pub fn atan_with_period_rational_prec_ref(x: &Rational, u: u64, prec: u64) -> (Self, Ordering) {
Self::atan_with_period_rational_prec_round_ref(x, u, prec, Nearest)
}
#[inline]
pub fn atan_pi_prec_round(self, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
self.atan_with_period_prec_round(2, prec, rm)
}
#[inline]
pub fn atan_pi_prec_round_ref(&self, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
self.atan_with_period_prec_round_ref(2, prec, rm)
}
#[inline]
pub fn atan_pi_prec(self, prec: u64) -> (Self, Ordering) {
self.atan_with_period_prec(2, prec)
}
#[inline]
pub fn atan_pi_prec_ref(&self, prec: u64) -> (Self, Ordering) {
self.atan_with_period_prec_ref(2, prec)
}
#[inline]
pub fn atan_pi_round(self, rm: RoundingMode) -> (Self, Ordering) {
self.atan_with_period_round(2, rm)
}
#[inline]
pub fn atan_pi_round_ref(&self, rm: RoundingMode) -> (Self, Ordering) {
self.atan_with_period_round_ref(2, rm)
}
#[inline]
pub fn atan_pi(self) -> Self {
let prec = self.significant_bits();
self.atan_pi_prec(prec).0
}
#[inline]
pub fn atan_pi_ref(&self) -> Self {
self.atan_pi_prec_ref(self.significant_bits()).0
}
#[inline]
pub fn atan_pi_prec_round_assign(&mut self, prec: u64, rm: RoundingMode) -> Ordering {
self.atan_with_period_prec_round_assign(2, prec, rm)
}
#[inline]
pub fn atan_pi_prec_assign(&mut self, prec: u64) -> Ordering {
self.atan_with_period_prec_assign(2, prec)
}
#[inline]
pub fn atan_pi_round_assign(&mut self, rm: RoundingMode) -> Ordering {
self.atan_with_period_round_assign(2, rm)
}
#[inline]
pub fn atan_pi_assign(&mut self) {
let prec = self.significant_bits();
self.atan_pi_prec_assign(prec);
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan_pi_rational_prec_round(
x: Rational,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
Self::atan_with_period_rational_prec_round_ref(&x, 2, prec, rm)
}
#[inline]
pub fn atan_pi_rational_prec_round_ref(
x: &Rational,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
Self::atan_with_period_rational_prec_round_ref(x, 2, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan_pi_rational_prec(x: Rational, prec: u64) -> (Self, Ordering) {
Self::atan_with_period_rational_prec_ref(&x, 2, prec)
}
#[inline]
pub fn atan_pi_rational_prec_ref(x: &Rational, prec: u64) -> (Self, Ordering) {
Self::atan_with_period_rational_prec_ref(x, 2, prec)
}
}
impl Atan for Float {
type Output = Self;
#[inline]
fn atan(self) -> Self {
let prec = self.significant_bits();
self.atan_prec_round(prec, Nearest).0
}
}
impl Atan for &Float {
type Output = Float;
#[inline]
fn atan(self) -> Float {
self.atan_prec_round_ref(self.significant_bits(), Nearest).0
}
}
impl AtanAssign for Float {
#[inline]
fn atan_assign(&mut self) {
let prec = self.significant_bits();
self.atan_prec_round_assign(prec, Nearest);
}
}
#[inline]
#[allow(clippy::type_repetition_in_bounds)]
pub fn primitive_float_atan<T: PrimitiveFloat>(x: T) -> T
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
emulate_float_to_float_fn(Float::atan_prec, x)
}
#[inline]
#[allow(clippy::type_repetition_in_bounds)]
pub fn primitive_float_atan_rational<T: PrimitiveFloat>(x: &Rational) -> T
where
Float: PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
emulate_rational_to_float_fn(Float::atan_rational_prec_ref, x)
}
#[inline]
#[allow(clippy::type_repetition_in_bounds)]
pub fn primitive_float_atan_with_period<T: PrimitiveFloat>(x: T, u: u64) -> T
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
emulate_float_to_float_fn(|x, prec| Float::atan_with_period_prec(x, u, prec), x)
}
#[inline]
#[allow(clippy::type_repetition_in_bounds)]
pub fn primitive_float_atan_with_period_rational<T: PrimitiveFloat>(x: &Rational, u: u64) -> T
where
Float: PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
emulate_rational_to_float_fn(
|x, prec| Float::atan_with_period_rational_prec_ref(x, u, prec),
x,
)
}
#[inline]
#[allow(clippy::type_repetition_in_bounds)]
pub fn primitive_float_atan_pi<T: PrimitiveFloat>(x: T) -> T
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
primitive_float_atan_with_period(x, 2)
}
#[inline]
#[allow(clippy::type_repetition_in_bounds)]
pub fn primitive_float_atan_pi_rational<T: PrimitiveFloat>(x: &Rational) -> T
where
Float: PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
primitive_float_atan_with_period_rational(x, 2)
}