use crate::float::arithmetic::atan::{
atan_rational_helper, atan_with_period_rational_helper, scaled_unsigned,
};
use crate::float::arithmetic::sin::{SCALE, SCALED_INPUT_EXPONENT, scaled_underflow};
use crate::{Float, emulate_float_float_to_float_fn, emulate_rational_rational_to_float_fn};
use core::cmp::Ordering::{self, Equal, Greater, Less};
use core::cmp::{max, min};
use malachite_base::num::arithmetic::traits::{
Abs, AbsAssign, Atan2, Atan2Assign, CeilingLogBase2, IsPowerOf2,
};
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, Zero as ZeroTrait,
};
use malachite_base::num::comparison::traits::{EqAbs, PartialOrdAbs};
use malachite_base::num::conversion::traits::ExactFrom;
use malachite_base::num::logic::traits::{SignificantBits, TrailingZeros};
use malachite_base::rounding_modes::RoundingMode::{self, *};
use malachite_nz::natural::arithmetic::float::round::float_can_round;
use malachite_nz::platform::Limb;
use malachite_q::Rational;
fn pi_div_2ui(i: u32, neg: bool, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
assert_ne!(rm, Exact, "Inexact atan2");
let (pi, o) = Float::pi_prec_round(prec, if neg { -rm } else { rm });
let q = pi >> i;
if neg { (-q, o.reverse()) } else { (q, o) }
}
fn three_pi_over_4(neg: bool, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
assert_ne!(rm, Exact, "Inexact atan2");
let mut w = prec + 10;
let mut increment = Limb::WIDTH;
loop {
let mut t = Float::pi_prec(w)
.0
.mul_prec(const { Float::const_from_unsigned(3) }, w)
.0;
t >>= 2u32;
if float_can_round(t.significand_ref().unwrap(), w - 2, prec, rm) {
let t = if neg { -t } else { t };
return Float::from_float_prec_round(t, prec, rm);
}
w += increment;
increment = w >> 1;
}
}
fn underflow(positive: bool, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
let away = match rm {
Ceiling => positive,
Floor => !positive,
Up | Nearest => true,
_ => false,
};
let min_positive = Float::min_positive_value_prec(prec);
match (positive, away) {
(true, true) => (min_positive, Greater),
(true, false) => (Float::ZERO, Less),
(false, true) => (-min_positive, Less),
(false, false) => (Float::NEGATIVE_ZERO, Greater),
}
}
fn quotient_underflows(y: &Float, x: &Float, exp_y: i64, exp_x: i64) -> bool {
match (exp_y - exp_x).cmp(&(Float::MIN_EXPONENT_I64 - 1)) {
Less => true,
Greater => false,
Equal => (y >> exp_y).lt_abs(&(x >> exp_x)),
}
}
fn atan2_huge_quotient(k: u64, negative: bool, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
let mut w = prec + 10;
let mut increment = Limb::WIDTH;
loop {
let v = Float::pi_prec(w).0 >> 1u32;
if float_can_round(v.significand_ref().unwrap(), min(w, k) - 1, prec, rm) {
return Float::from_float_prec_round(if negative { -v } else { v }, prec, rm);
}
w += increment;
increment = w >> 1;
}
}
fn atan2_prec_round_normal_ref(
y: &Float,
x: &Float,
prec: u64,
rm: RoundingMode,
) -> (Float, Ordering) {
assert_ne!(rm, Exact, "Inexact atan2");
let exp_y = i64::from(y.get_exponent().unwrap());
let exp_x = i64::from(x.get_exponent().unwrap());
let x_positive = *x > 0u32;
if x_positive && x.significand_ref().unwrap().is_power_of_2() {
let shifted = exp_y - exp_x + 1;
if (Float::MIN_EXPONENT_I64..=Float::MAX_EXPONENT_I64).contains(&shifted) {
return (y >> (exp_x - 1)).atan_prec_round(prec, rm);
}
}
let y_negative = *y < 0u32;
if exp_y - exp_x >= Float::MAX_EXPONENT_I64 {
return atan2_huge_quotient(u64::exact_from(exp_y - exp_x - 1), y_negative, prec, rm);
}
let mut w = prec + 3 + prec.ceiling_log_base_2();
let mut increment = Limb::WIDTH;
if x_positive {
loop {
let (t, div_o) = y.div_prec_ref_ref(x, w);
if div_o == Equal {
return t.atan_prec_round(prec, rm);
}
if quotient_underflows(y, x, exp_y, exp_x) {
let rm = if rm == Nearest && t == 0u32 { Down } else { rm };
return underflow(!y_negative, prec, rm);
}
let mut t = t;
t.atan_prec_assign(w);
if float_can_round(t.significand_ref().unwrap(), w - 2, prec, rm) {
return Float::from_float_prec_round(t, prec, rm);
}
w += increment;
increment = w >> 1;
}
}
loop {
let mut t = y.div_prec_ref_ref(x, w).0.abs();
t.atan_prec_assign(w);
let pi = Float::pi_prec(w).0;
let e = if t == 0u32 {
Float::MIN_EXPONENT_I64 - 1
} else {
i64::from(t.get_exponent().unwrap())
};
let exp_pi = i64::from(pi.get_exponent().unwrap());
let t = pi.sub_prec(t, w).0;
let t = if y_negative { -t } else { t };
let exp_t = i64::from(t.get_exponent().unwrap());
let e = max(max(exp_pi - exp_t - 1, e - exp_t + 1), -1) + 2;
if e < i64::exact_from(w)
&& float_can_round(
t.significand_ref().unwrap(),
w - u64::exact_from(e),
prec,
rm,
)
{
return Float::from_float_prec_round(t, prec, rm);
}
w += increment;
increment = w >> 1;
}
}
fn atan2_rational_prec_round_normal_ref(
y: &Rational,
x: &Rational,
prec: u64,
rm: RoundingMode,
) -> (Float, Ordering) {
assert_ne!(rm, Exact, "Inexact atan2_rational");
let q = y / x;
if *x > 0u32 {
return atan_rational_helper(&q, prec, rm);
}
let y_negative = *y < 0u32;
let aq = q.abs();
let mut w = prec + 3 + prec.ceiling_log_base_2();
let mut increment = Limb::WIDTH;
loop {
let t = atan_rational_helper(&aq, w, Nearest).0;
let pi = Float::pi_prec(w).0;
let exp_pi = i64::from(pi.get_exponent().unwrap());
let e = if t == 0u32 {
Float::MIN_EXPONENT_I64 - 1
} else {
i64::from(t.get_exponent().unwrap())
};
let t = pi.sub_prec(t, w).0;
let t = if y_negative { -t } else { t };
let exp_t = i64::from(t.get_exponent().unwrap());
let e = max(max(exp_pi - exp_t - 1, e - exp_t + 1), -1) + 2;
if e < i64::exact_from(w)
&& float_can_round(
t.significand_ref().unwrap(),
w - u64::exact_from(e),
prec,
rm,
)
{
return Float::from_float_prec_round(t, prec, rm);
}
w += increment;
increment = w >> 1;
}
}
const ULSIZE: u64 = 64;
const AUX_PREC: u64 = ULSIZE + 2;
fn atan2u_aux2(u: u64, k: u32, positive: bool, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
let t = Float::from_unsigned_prec_round(u, AUX_PREC, Exact)
.0
.mul_prec_round(const { Float::const_from_unsigned(3) }, AUX_PREC, Exact)
.0
>> k;
Float::from_float_prec_round(if positive { t } else { -t }, prec, rm)
}
fn atan2u_aux3(u: u64, positive: bool, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
let mut t = Float::from_unsigned_prec_round(u, max(prec + 2, ULSIZE), Exact).0 >> 1u32;
t.decrement();
Float::from_float_prec_round(if positive { t } else { -t }, prec, rm)
}
fn atan2u_aux4(
u: u64,
x_positive: bool,
y_positive: bool,
prec: u64,
rm: RoundingMode,
) -> (Float, Ordering) {
let w = if prec > ULSIZE { prec + 2 } else { AUX_PREC };
let mut t = Float::from_unsigned_prec_round(u, w, Exact).0 >> 2u32;
if x_positive {
t.decrement();
} else {
t.increment();
}
Float::from_float_prec_round(if y_positive { t } else { -t }, prec, rm)
}
fn atan2u_tiny(
y: &Float,
x: &Float,
u: u64,
positive: bool,
prec: u64,
rm: RoundingMode,
) -> (Float, Ordering) {
let ys = y << SCALE;
let xa = x.clone();
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 = ys.div_prec_round_ref_ref(&xa, w, Up).0;
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;
}
}
fn atan2_with_period_prec_round_normal_ref(
y: &Float,
x: &Float,
u: u64,
prec: u64,
rm: RoundingMode,
) -> (Float, Ordering) {
assert_ne!(rm, Exact, "Inexact atan2_with_period");
let x_positive = *x > 0u32;
let y_positive = *y > 0u32;
let exp_y = i64::from(y.get_exponent().unwrap());
let exp_x = i64::from(x.get_exponent().unwrap());
let d = exp_y - exp_x;
let p = i64::exact_from(prec);
if i64::exact_from(u.significant_bits() - TrailingZeros::trailing_zeros(u)) <= p + 1 {
if d >= p + 2 {
return atan2u_aux4(u, x_positive, y_positive, prec, rm);
}
if !x_positive && d < -p {
return atan2u_aux3(u, y_positive, prec, rm);
}
}
if d <= SCALED_INPUT_EXPONENT {
return if x_positive {
atan2u_tiny(y, x, u, y_positive, prec, rm)
} else {
atan2u_aux3(u, y_positive, prec, rm)
};
}
let log_u = u.ceiling_log_base_2();
let mut w = prec + prec.ceiling_log_base_2() + 10;
let mut increment = Limb::WIDTH;
loop {
let t = y.div_prec_ref_ref(x, w).0;
if !t.is_finite() {
return atan2u_aux4(u, x_positive, y_positive, prec, rm);
}
let mut t = t;
t.abs_assign();
let exp_t = i64::from(t.get_exponent().unwrap());
t.atan_with_period_prec_assign(u, w);
let e = if exp_t < 1 { 0 } else { exp_t - 1 };
let mut e = exp_t - (e << 1) + i64::exact_from(log_u) - 2;
let mut exp_t = i64::from(t.get_exponent().unwrap());
e = max(e, exp_t);
if !x_positive {
t <<= 1u32; t = Float::from(u).sub_prec(t, w).0;
exp_t = i64::from(t.get_exponent().unwrap());
e = max(exp_t - 1, e + 1);
t >>= 1u32;
exp_t = i64::from(t.get_exponent().unwrap());
}
e -= exp_t;
let t = if y_positive { t } else { -t };
let err = min(i64::exact_from(w), i64::exact_from(w) - e);
if err > 0 && float_can_round(t.significand_ref().unwrap(), u64::exact_from(err), prec, rm)
{
return Float::from_float_prec_round(t, prec, rm);
}
w += increment;
increment = w >> 1;
}
}
fn atan2_with_period_rational_prec_round_normal_ref(
y: &Rational,
x: &Rational,
u: u64,
prec: u64,
rm: RoundingMode,
) -> (Float, Ordering) {
assert_ne!(rm, Exact, "Inexact atan2_with_period_rational");
let q = y / x;
if *x > 0u32 {
return atan_with_period_rational_helper(&q, u, prec, rm);
}
let y_positive = *y > 0u32;
let aq = q.abs();
let d = aq.floor_log_base_2_abs() + 1;
let p = i64::exact_from(prec);
if d <= SCALED_INPUT_EXPONENT {
return atan2u_aux3(u, y_positive, prec, rm);
}
if i64::exact_from(u.significant_bits() - TrailingZeros::trailing_zeros(u)) <= p + 1 {
if d >= p + 2 {
return atan2u_aux4(u, false, y_positive, prec, rm);
}
if d < -p {
return atan2u_aux3(u, y_positive, prec, rm);
}
}
let mut w = prec + prec.ceiling_log_base_2() + 10;
let mut increment = Limb::WIDTH;
loop {
let t = atan_with_period_rational_helper(&aq, u, w, Nearest).0;
let mut e = i64::from(t.get_exponent().unwrap());
let t = Float::from(u).sub_prec(t << 1u32, w).0;
let exp_t = i64::from(t.get_exponent().unwrap());
e = max(exp_t - 1, e + 1);
let t = t >> 1u32;
let exp_t = i64::from(t.get_exponent().unwrap());
e -= exp_t;
let t = if y_positive { t } else { -t };
let err = min(i64::exact_from(w), i64::exact_from(w) - e);
if err > 0 && float_can_round(t.significand_ref().unwrap(), u64::exact_from(err), prec, rm)
{
return Float::from_float_prec_round(t, prec, rm);
}
w += increment;
increment = w >> 1;
}
}
const fn signed_zero(negative: bool) -> (Float, Ordering) {
(
if negative {
Float::NEGATIVE_ZERO
} else {
Float::ZERO
},
Equal,
)
}
impl Float {
pub fn atan2_prec_round_ref_ref(
&self,
other: &Self,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
assert_ne!(prec, 0);
let (y, x) = (self, other);
if y.is_nan() || x.is_nan() {
return (Self::NAN, Equal);
}
let y_negative = y.is_sign_negative();
let x_negative = x.is_sign_negative();
if *y == 0u32 {
return if x_negative {
pi_div_2ui(0, y_negative, prec, rm)
} else {
signed_zero(y_negative)
};
}
if *x == 0u32 {
return pi_div_2ui(1, y_negative, prec, rm);
}
if !y.is_finite() {
return if x.is_finite() {
pi_div_2ui(1, y_negative, prec, rm)
} else if x_negative {
three_pi_over_4(y_negative, prec, rm)
} else {
pi_div_2ui(2, y_negative, prec, rm)
};
}
if !x.is_finite() {
return if x_negative {
pi_div_2ui(0, y_negative, prec, rm)
} else {
signed_zero(y_negative)
};
}
atan2_prec_round_normal_ref(y, x, prec, rm)
}
pub fn atan2_with_period_prec_round_ref_ref(
&self,
other: &Self,
u: u64,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
assert_ne!(prec, 0);
let (y, x) = (self, other);
if y.is_nan() || x.is_nan() {
return (Self::NAN, Equal);
}
let y_positive = y.is_sign_positive();
let x_positive = x.is_sign_positive();
if !x.is_finite() {
if !y.is_finite() {
return if x_positive {
scaled_unsigned(u, 3, y_positive, prec, rm)
} else {
atan2u_aux2(u, 3, y_positive, prec, rm)
};
}
return if x_positive {
signed_zero(!y_positive)
} else {
scaled_unsigned(u, 1, y_positive, prec, rm)
};
}
if !y.is_finite() {
return scaled_unsigned(u, 2, y_positive, prec, rm);
}
if *y == 0u32 {
return if x_positive {
signed_zero(!y_positive)
} else {
scaled_unsigned(u, 1, y_positive, prec, rm)
};
}
if *x == 0u32 {
return scaled_unsigned(u, 2, y_positive, prec, rm);
}
if y.eq_abs(x) {
return if x_positive {
scaled_unsigned(u, 3, y_positive, prec, rm)
} else {
atan2u_aux2(u, 3, y_positive, prec, rm)
};
}
if u == 0 {
return signed_zero(!y_positive);
}
atan2_with_period_prec_round_normal_ref(y, x, u, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_with_period_prec_round(
self,
other: Self,
u: u64,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
self.atan2_with_period_prec_round_ref_ref(&other, u, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_with_period_prec_round_val_ref(
self,
other: &Self,
u: u64,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
self.atan2_with_period_prec_round_ref_ref(other, u, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_with_period_prec_round_ref_val(
&self,
other: Self,
u: u64,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
self.atan2_with_period_prec_round_ref_ref(&other, u, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_with_period_prec(self, other: Self, u: u64, prec: u64) -> (Self, Ordering) {
self.atan2_with_period_prec_ref_ref(&other, u, prec)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_with_period_prec_val_ref(
self,
other: &Self,
u: u64,
prec: u64,
) -> (Self, Ordering) {
self.atan2_with_period_prec_ref_ref(other, u, prec)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_with_period_prec_ref_val(
&self,
other: Self,
u: u64,
prec: u64,
) -> (Self, Ordering) {
self.atan2_with_period_prec_ref_ref(&other, u, prec)
}
#[inline]
pub fn atan2_with_period_prec_ref_ref(
&self,
other: &Self,
u: u64,
prec: u64,
) -> (Self, Ordering) {
self.atan2_with_period_prec_round_ref_ref(other, u, prec, Nearest)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_with_period_round(
self,
other: Self,
u: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
let prec = max(self.significant_bits(), other.significant_bits());
self.atan2_with_period_prec_round_ref_ref(&other, u, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_with_period_round_val_ref(
self,
other: &Self,
u: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
let prec = max(self.significant_bits(), other.significant_bits());
self.atan2_with_period_prec_round_ref_ref(other, u, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_with_period_round_ref_val(
&self,
other: Self,
u: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
let prec = max(self.significant_bits(), other.significant_bits());
self.atan2_with_period_prec_round_ref_ref(&other, u, prec, rm)
}
#[inline]
pub fn atan2_with_period_round_ref_ref(
&self,
other: &Self,
u: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
let prec = max(self.significant_bits(), other.significant_bits());
self.atan2_with_period_prec_round_ref_ref(other, u, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_with_period_prec_round_assign(
&mut self,
other: Self,
u: u64,
prec: u64,
rm: RoundingMode,
) -> Ordering {
let (t, o) = self.atan2_with_period_prec_round_ref_ref(&other, u, prec, rm);
*self = t;
o
}
#[inline]
pub fn atan2_with_period_prec_round_assign_ref(
&mut self,
other: &Self,
u: u64,
prec: u64,
rm: RoundingMode,
) -> Ordering {
let (t, o) = self.atan2_with_period_prec_round_ref_ref(other, u, prec, rm);
*self = t;
o
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_with_period_prec_assign(&mut self, other: Self, u: u64, prec: u64) -> Ordering {
let (t, o) = self.atan2_with_period_prec_ref_ref(&other, u, prec);
*self = t;
o
}
#[inline]
pub fn atan2_with_period_prec_assign_ref(
&mut self,
other: &Self,
u: u64,
prec: u64,
) -> Ordering {
let (t, o) = self.atan2_with_period_prec_ref_ref(other, u, prec);
*self = t;
o
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_with_period_round_assign(
&mut self,
other: Self,
u: u64,
rm: RoundingMode,
) -> Ordering {
let prec = max(self.significant_bits(), other.significant_bits());
let (t, o) = self.atan2_with_period_prec_round_ref_ref(&other, u, prec, rm);
*self = t;
o
}
#[inline]
pub fn atan2_with_period_round_assign_ref(
&mut self,
other: &Self,
u: u64,
rm: RoundingMode,
) -> Ordering {
let prec = max(self.significant_bits(), other.significant_bits());
let (t, o) = self.atan2_with_period_prec_round_ref_ref(other, u, prec, rm);
*self = t;
o
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_prec_round(self, other: Self, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
self.atan2_prec_round_ref_ref(&other, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_prec_round_val_ref(
self,
other: &Self,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
self.atan2_prec_round_ref_ref(other, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_prec_round_ref_val(
&self,
other: Self,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
self.atan2_prec_round_ref_ref(&other, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_prec(self, other: Self, prec: u64) -> (Self, Ordering) {
self.atan2_prec_round_ref_ref(&other, prec, Nearest)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_prec_val_ref(self, other: &Self, prec: u64) -> (Self, Ordering) {
self.atan2_prec_round_ref_ref(other, prec, Nearest)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_prec_ref_val(&self, other: Self, prec: u64) -> (Self, Ordering) {
self.atan2_prec_round_ref_ref(&other, prec, Nearest)
}
#[inline]
pub fn atan2_prec_ref_ref(&self, other: &Self, prec: u64) -> (Self, Ordering) {
self.atan2_prec_round_ref_ref(other, prec, Nearest)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_round(self, other: Self, rm: RoundingMode) -> (Self, Ordering) {
let prec = max(self.significant_bits(), other.significant_bits());
self.atan2_prec_round_ref_ref(&other, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_round_val_ref(self, other: &Self, rm: RoundingMode) -> (Self, Ordering) {
let prec = max(self.significant_bits(), other.significant_bits());
self.atan2_prec_round_ref_ref(other, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_round_ref_val(&self, other: Self, rm: RoundingMode) -> (Self, Ordering) {
let prec = max(self.significant_bits(), other.significant_bits());
self.atan2_prec_round_ref_ref(&other, prec, rm)
}
#[inline]
pub fn atan2_round_ref_ref(&self, other: &Self, rm: RoundingMode) -> (Self, Ordering) {
let prec = max(self.significant_bits(), other.significant_bits());
self.atan2_prec_round_ref_ref(other, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_prec_round_assign(
&mut self,
other: Self,
prec: u64,
rm: RoundingMode,
) -> Ordering {
let (t, o) = self.atan2_prec_round_ref_ref(&other, prec, rm);
*self = t;
o
}
#[inline]
pub fn atan2_prec_round_assign_ref(
&mut self,
other: &Self,
prec: u64,
rm: RoundingMode,
) -> Ordering {
let (t, o) = self.atan2_prec_round_ref_ref(other, prec, rm);
*self = t;
o
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_prec_assign(&mut self, other: Self, prec: u64) -> Ordering {
let (t, o) = self.atan2_prec_ref_ref(&other, prec);
*self = t;
o
}
#[inline]
pub fn atan2_prec_assign_ref(&mut self, other: &Self, prec: u64) -> Ordering {
let (t, o) = self.atan2_prec_ref_ref(other, prec);
*self = t;
o
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_round_assign(&mut self, other: Self, rm: RoundingMode) -> Ordering {
let prec = max(self.significant_bits(), other.significant_bits());
let (t, o) = self.atan2_prec_round_ref_ref(&other, prec, rm);
*self = t;
o
}
#[inline]
pub fn atan2_round_assign_ref(&mut self, other: &Self, rm: RoundingMode) -> Ordering {
let prec = max(self.significant_bits(), other.significant_bits());
let (t, o) = self.atan2_prec_round_ref_ref(other, prec, rm);
*self = t;
o
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_rational_prec_round(
y: Rational,
x: Rational,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
Self::atan2_rational_prec_round_ref(&y, &x, prec, rm)
}
pub fn atan2_rational_prec_round_ref(
y: &Rational,
x: &Rational,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
assert_ne!(prec, 0);
if *y == 0u32 {
return if *x < 0u32 {
pi_div_2ui(0, false, prec, rm)
} else {
(Self::ZERO, Equal)
};
}
if *x == 0u32 {
return pi_div_2ui(1, *y < 0u32, prec, rm);
}
atan2_rational_prec_round_normal_ref(y, x, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_rational_prec(y: Rational, x: Rational, prec: u64) -> (Self, Ordering) {
Self::atan2_rational_prec_round_ref(&y, &x, prec, Nearest)
}
#[inline]
pub fn atan2_rational_prec_ref(y: &Rational, x: &Rational, prec: u64) -> (Self, Ordering) {
Self::atan2_rational_prec_round_ref(y, x, prec, Nearest)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_with_period_rational_prec_round(
y: Rational,
x: Rational,
u: u64,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
Self::atan2_with_period_rational_prec_round_ref(&y, &x, u, prec, rm)
}
pub fn atan2_with_period_rational_prec_round_ref(
y: &Rational,
x: &Rational,
u: u64,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
assert_ne!(prec, 0);
if *y == 0u32 {
return if *x < 0u32 {
scaled_unsigned(u, 1, true, prec, rm)
} else {
(Self::ZERO, Equal)
};
}
let y_positive = *y > 0u32;
if *x == 0u32 {
return scaled_unsigned(u, 2, y_positive, prec, rm);
}
if y.eq_abs(x) {
return if *x > 0u32 {
scaled_unsigned(u, 3, y_positive, prec, rm)
} else {
atan2u_aux2(u, 3, y_positive, prec, rm)
};
}
if u == 0 {
return (Self::ZERO, Equal);
}
atan2_with_period_rational_prec_round_normal_ref(y, x, u, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_with_period_rational_prec(
y: Rational,
x: Rational,
u: u64,
prec: u64,
) -> (Self, Ordering) {
Self::atan2_with_period_rational_prec_round_ref(&y, &x, u, prec, Nearest)
}
#[inline]
pub fn atan2_with_period_rational_prec_ref(
y: &Rational,
x: &Rational,
u: u64,
prec: u64,
) -> (Self, Ordering) {
Self::atan2_with_period_rational_prec_round_ref(y, x, u, prec, Nearest)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_pi_prec_round(self, other: Self, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
self.atan2_with_period_prec_round(other, 2, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_pi_prec_round_val_ref(
self,
other: &Self,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
self.atan2_with_period_prec_round_val_ref(other, 2, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_pi_prec_round_ref_val(
&self,
other: Self,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
self.atan2_with_period_prec_round_ref_val(other, 2, prec, rm)
}
#[inline]
pub fn atan2_pi_prec_round_ref_ref(
&self,
other: &Self,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
self.atan2_with_period_prec_round_ref_ref(other, 2, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_pi_prec(self, other: Self, prec: u64) -> (Self, Ordering) {
self.atan2_with_period_prec(other, 2, prec)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_pi_prec_val_ref(self, other: &Self, prec: u64) -> (Self, Ordering) {
self.atan2_with_period_prec_val_ref(other, 2, prec)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_pi_prec_ref_val(&self, other: Self, prec: u64) -> (Self, Ordering) {
self.atan2_with_period_prec_ref_val(other, 2, prec)
}
#[inline]
pub fn atan2_pi_prec_ref_ref(&self, other: &Self, prec: u64) -> (Self, Ordering) {
self.atan2_with_period_prec_ref_ref(other, 2, prec)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_pi_round(self, other: Self, rm: RoundingMode) -> (Self, Ordering) {
self.atan2_with_period_round(other, 2, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_pi_round_val_ref(self, other: &Self, rm: RoundingMode) -> (Self, Ordering) {
self.atan2_with_period_round_val_ref(other, 2, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_pi_round_ref_val(&self, other: Self, rm: RoundingMode) -> (Self, Ordering) {
self.atan2_with_period_round_ref_val(other, 2, rm)
}
#[inline]
pub fn atan2_pi_round_ref_ref(&self, other: &Self, rm: RoundingMode) -> (Self, Ordering) {
self.atan2_with_period_round_ref_ref(other, 2, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_pi_prec_round_assign(
&mut self,
other: Self,
prec: u64,
rm: RoundingMode,
) -> Ordering {
self.atan2_with_period_prec_round_assign(other, 2, prec, rm)
}
#[inline]
pub fn atan2_pi_prec_round_assign_ref(
&mut self,
other: &Self,
prec: u64,
rm: RoundingMode,
) -> Ordering {
self.atan2_with_period_prec_round_assign_ref(other, 2, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_pi_prec_assign(&mut self, other: Self, prec: u64) -> Ordering {
self.atan2_with_period_prec_assign(other, 2, prec)
}
#[inline]
pub fn atan2_pi_prec_assign_ref(&mut self, other: &Self, prec: u64) -> Ordering {
self.atan2_with_period_prec_assign_ref(other, 2, prec)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_pi_round_assign(&mut self, other: Self, rm: RoundingMode) -> Ordering {
self.atan2_with_period_round_assign(other, 2, rm)
}
#[inline]
pub fn atan2_pi_round_assign_ref(&mut self, other: &Self, rm: RoundingMode) -> Ordering {
self.atan2_with_period_round_assign_ref(other, 2, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_pi_rational_prec_round(
y: Rational,
x: Rational,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
Self::atan2_with_period_rational_prec_round(y, x, 2, prec, rm)
}
#[inline]
pub fn atan2_pi_rational_prec_round_ref(
y: &Rational,
x: &Rational,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
Self::atan2_with_period_rational_prec_round_ref(y, x, 2, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn atan2_pi_rational_prec(y: Rational, x: Rational, prec: u64) -> (Self, Ordering) {
Self::atan2_with_period_rational_prec(y, x, 2, prec)
}
#[inline]
pub fn atan2_pi_rational_prec_ref(y: &Rational, x: &Rational, prec: u64) -> (Self, Ordering) {
Self::atan2_with_period_rational_prec_ref(y, x, 2, prec)
}
}
impl Atan2<Self> for Float {
type Output = Self;
#[inline]
fn atan2(self, other: Self) -> Self {
self.atan2_round_ref_ref(&other, Nearest).0
}
}
impl Atan2<&Self> for Float {
type Output = Self;
#[inline]
fn atan2(self, other: &Self) -> Self {
self.atan2_round_ref_ref(other, Nearest).0
}
}
impl Atan2<Float> for &Float {
type Output = Float;
#[inline]
fn atan2(self, other: Float) -> Float {
self.atan2_round_ref_ref(&other, Nearest).0
}
}
impl Atan2<&Float> for &Float {
type Output = Float;
#[inline]
fn atan2(self, other: &Float) -> Float {
self.atan2_round_ref_ref(other, Nearest).0
}
}
impl Atan2Assign<Self> for Float {
#[inline]
fn atan2_assign(&mut self, other: Self) {
self.atan2_round_assign_ref(&other, Nearest);
}
}
impl Atan2Assign<&Self> for Float {
#[inline]
fn atan2_assign(&mut self, other: &Self) {
self.atan2_round_assign_ref(other, Nearest);
}
}
#[inline]
#[allow(clippy::type_repetition_in_bounds)]
pub fn primitive_float_atan2<T: PrimitiveFloat>(y: T, x: T) -> T
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float>,
{
emulate_float_float_to_float_fn(|y, x, prec| y.atan2_prec_ref_ref(&x, prec), y, x)
}
#[inline]
#[allow(clippy::type_repetition_in_bounds)]
pub fn primitive_float_atan2_rational<T: PrimitiveFloat>(y: &Rational, x: &Rational) -> T
where
Float: PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float>,
{
emulate_rational_rational_to_float_fn(Float::atan2_rational_prec_ref, y, x)
}
#[inline]
#[allow(clippy::type_repetition_in_bounds)]
pub fn primitive_float_atan2_with_period<T: PrimitiveFloat>(y: T, x: T, u: u64) -> T
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float>,
{
emulate_float_float_to_float_fn(
|y, x, prec| y.atan2_with_period_prec_ref_ref(&x, u, prec),
y,
x,
)
}
#[inline]
#[allow(clippy::type_repetition_in_bounds)]
pub fn primitive_float_atan2_with_period_rational<T: PrimitiveFloat>(
y: &Rational,
x: &Rational,
u: u64,
) -> T
where
Float: PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float>,
{
emulate_rational_rational_to_float_fn(
|y, x, prec| Float::atan2_with_period_rational_prec_ref(y, x, u, prec),
y,
x,
)
}
#[inline]
#[allow(clippy::type_repetition_in_bounds)]
pub fn primitive_float_atan2_pi<T: PrimitiveFloat>(y: T, x: T) -> T
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float>,
{
primitive_float_atan2_with_period(y, x, 2)
}
#[inline]
#[allow(clippy::type_repetition_in_bounds)]
pub fn primitive_float_atan2_pi_rational<T: PrimitiveFloat>(y: &Rational, x: &Rational) -> T
where
Float: PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float>,
{
primitive_float_atan2_with_period_rational(y, x, 2)
}