use crate::InnerFloat::{Finite, Infinity, NaN, Zero};
use crate::float::arithmetic::cos::{
reduce_huge, round_bracket, signed_constant, sin_bound, trig_near_zero_bracket,
trig_rational_near_zero_bracket, trig_turns_near_zero_bracket,
};
use crate::float::arithmetic::round_near_x::{
LEADING_TERM_MIN_EXPONENT, float_round_near_x, round_rational_leading_term,
};
use crate::float::arithmetic::sin::{SCALE, SCALED_INPUT_EXPONENT, scaled_underflow};
use crate::float::arithmetic::sin_cos::{
sin_cos_rational_helper, sin_cos_turns_helper, sin_cos_with_period_prec_round_normal_ref,
};
use crate::float::conversion::string::set_str::overflow;
use crate::{Float, emulate_float_to_float_fn, emulate_rational_to_float_fn};
use core::cmp::Ordering::{self, Equal};
use core::cmp::{max, min};
use malachite_base::num::arithmetic::traits::{
Abs, AddMul, CeilingLogBase2, IsPowerOf2, Mod, Parity, Pow, PowerOf2, Reciprocal, Square, Tan,
TanAssign,
};
use malachite_base::num::basic::floats::PrimitiveFloat;
use malachite_base::num::basic::integers::PrimitiveInt;
use malachite_base::num::basic::traits::{
Infinity as InfinityTrait, NaN as NaNTrait, NegativeInfinity,
NegativeZero as NegativeZeroTrait, One, Zero as ZeroTrait,
};
use malachite_base::num::comparison::traits::PartialOrdAbs;
use malachite_base::num::conversion::traits::{ExactFrom, RoundingFrom};
use malachite_base::num::logic::traits::SignificantBits;
use malachite_base::rounding_modes::RoundingMode::{self, *};
use malachite_nz::integer::Integer;
use malachite_nz::natural::arithmetic::float::round::float_can_round;
use malachite_nz::platform::Limb;
use malachite_q::Rational;
pub(crate) const MIN_SETTLED_EXPONENT: i64 = Float::MIN_EXPONENT_I64 + 1;
pub(crate) const MAX_SETTLED_EXPONENT: i64 = Float::MAX_EXPONENT_I64 - 1;
pub(crate) const MAX_CANCEL: u64 = Float::MAX_EXPONENT as u64 + 2;
pub(crate) fn nearest_bracket(v: &Float, m: u64) -> (Rational, Rational) {
if *v == 0u32 {
return (
Rational::ZERO,
Rational::exact_from(&Float::min_positive_value_prec(1)) >> 1u32,
);
}
let exp = i64::from(v.get_exponent().unwrap());
let abs = Rational::exact_from(v).abs();
let half_ulp = Rational::power_of_2(exp - i64::exact_from(m) - 1);
if exp == Float::MIN_EXPONENT_I64 && v.significand_ref().unwrap().is_power_of_2() {
(Rational::power_of_2(exp - 2), abs + half_ulp)
} else {
(&abs - &half_ulp, abs + half_ulp)
}
}
fn tan_bracket(
x: &Float,
s: &Float,
c: &Float,
m: u64,
prec: u64,
rm: RoundingMode,
) -> Option<(Float, Ordering)> {
let negative = s.is_sign_negative() != c.is_sign_negative();
if *c == 0u32
|| (c.get_exponent() == Some(Float::MIN_EXPONENT)
&& c.significand_ref().unwrap().is_power_of_2())
{
return Some(overflow(!negative, prec, rm));
}
let (c_lo, c_hi) = nearest_bracket(c, m);
let (s_lo, s_hi) = if *s == 0u32 {
let (lo, hi) = trig_near_zero_bracket(x, m + 64, MAX_CANCEL, false);
if lo < 0u32 { (-hi, -lo) } else { (lo, hi) }
} else {
nearest_bracket(s, m)
};
round_bracket_signed_by(negative, s_lo / c_hi, s_hi / c_lo, prec, rm)
}
fn tan_prec_round_normal_ref(x: &Float, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
assert_ne!(rm, Exact, "Inexact tan");
let exp_x = i64::from(x.get_exponent().unwrap());
let err1 = -(exp_x << 1);
if err1 > 0 {
let err = u64::exact_from(err1) + 1;
if err > prec + 1
&& let Some(result) = float_round_near_x(x, min(err, prec + 2), true, prec, rm)
{
return result;
}
}
let mut m = prec + prec.ceiling_log_base_2() + 13;
let mut increment = Limb::WIDTH;
loop {
let (s, c, _, _) = x.sin_cos_prec_ref(m);
let q = if s == 0u32 || c == 0u32 {
None
} else {
Some(s.div_prec_ref_ref(&c, m).0)
};
let exp_q = q.as_ref().and_then(Float::get_exponent).map(i64::from);
match exp_q {
Some(e) if e > MIN_SETTLED_EXPONENT && e < MAX_SETTLED_EXPONENT => {
let q = q.unwrap();
if float_can_round(q.significand_ref().unwrap(), m - 2, prec, rm) {
return Float::from_float_prec_round(q, prec, rm);
}
}
_ => {
if let Some(result) = tan_bracket(x, &s, &c, m, prec, rm) {
return result;
}
}
}
m += increment;
increment = m >> 1;
}
}
impl Float {
#[inline]
pub fn tan_prec_round(self, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
self.tan_prec_round_ref(prec, rm)
}
pub fn tan_prec_round_ref(&self, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
assert_ne!(prec, 0);
match &self.0 {
NaN | Infinity { .. } => (Self::NAN, Equal),
Zero { .. } => (self.clone(), Equal),
Finite { .. } => tan_prec_round_normal_ref(self, prec, rm),
}
}
#[inline]
pub fn tan_prec(self, prec: u64) -> (Self, Ordering) {
self.tan_prec_round(prec, Nearest)
}
#[inline]
pub fn tan_prec_ref(&self, prec: u64) -> (Self, Ordering) {
self.tan_prec_round_ref(prec, Nearest)
}
#[inline]
pub fn tan_round(self, rm: RoundingMode) -> (Self, Ordering) {
let prec = self.significant_bits();
self.tan_prec_round(prec, rm)
}
#[inline]
pub fn tan_round_ref(&self, rm: RoundingMode) -> (Self, Ordering) {
self.tan_prec_round_ref(self.significant_bits(), rm)
}
#[inline]
pub fn tan_prec_round_assign(&mut self, prec: u64, rm: RoundingMode) -> Ordering {
let o;
(*self, o) = self.tan_prec_round_ref(prec, rm);
o
}
#[inline]
pub fn tan_prec_assign(&mut self, prec: u64) -> Ordering {
self.tan_prec_round_assign(prec, Nearest)
}
#[inline]
pub fn tan_round_assign(&mut self, rm: RoundingMode) -> Ordering {
let prec = self.significant_bits();
self.tan_prec_round_assign(prec, rm)
}
}
pub(crate) fn tan_rational_helper(x: &Rational, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
assert_ne!(rm, Exact, "Inexact tan");
let exp_x = x.floor_log_base_2_abs() + 1; 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, true, prec, rm);
}
if exp_x < 0 && -(exp_x << 2) > i64::exact_from(prec) + 3 {
let ax = x.abs();
let ax3 = (&ax).pow(3u64);
let lo = &ax + &ax3 / const { Rational::const_from_unsigned(3) };
let hi = (&lo).add_mul(&ax3, &(&ax).square());
if let Some(result) = round_bracket_signed(x, lo, hi, prec, rm) {
return result;
}
if exp_x <= const { Float::MIN_EXPONENT_I64 + 2 } {
return tan_rational_tiny(x, &ax, prec, rm);
}
}
let mut m = prec + prec.ceiling_log_base_2() + 13;
let mut increment = Limb::WIDTH;
loop {
let (s, c, _, _) = sin_cos_rational_helper(x, m, Nearest);
let q = if s == 0u32 || c == 0u32 {
None
} else {
Some(s.div_prec_ref_ref(&c, m).0)
};
let exp_q = q.as_ref().and_then(Float::get_exponent).map(i64::from);
match exp_q {
Some(e) if e > MIN_SETTLED_EXPONENT && e < MAX_SETTLED_EXPONENT => {
let q = q.unwrap();
if float_can_round(q.significand_ref().unwrap(), m - 2, prec, rm) {
return Float::from_float_prec_round(q, prec, rm);
}
}
_ => {
if let Some(result) = tan_rational_bracket(x, exp_x, &s, &c, m, prec, rm) {
return result;
}
}
}
m += increment;
increment = m >> 1;
}
}
pub(crate) fn round_bracket_signed(
x: &Rational,
lo: Rational,
hi: Rational,
prec: u64,
rm: RoundingMode,
) -> Option<(Float, Ordering)> {
round_bracket_signed_by(*x < 0u32, lo, hi, prec, rm)
}
fn reciprocal_of_down_bracket(
d: &Float,
m: u64,
prec: u64,
rm: RoundingMode,
) -> Option<(Float, Ordering)> {
let negative = d.is_sign_negative();
if *d == 0u32 {
return Some(overflow(!negative, prec, rm));
}
let exp_d = i64::from(d.get_exponent().unwrap());
let lo = Rational::exact_from(d).abs();
let hi = &lo + Rational::power_of_2(exp_d - i64::exact_from(m));
round_bracket_signed_by(negative, hi.reciprocal(), lo.reciprocal(), prec, rm)
}
pub(crate) fn reciprocal_ziv_loop<D: FnMut(u64) -> Float>(
prec: u64,
rm: RoundingMode,
mut denominator: D,
) -> (Float, Ordering) {
let mut m = prec + prec.ceiling_log_base_2() + 3;
let mut increment = Limb::WIDTH;
loop {
let d = denominator(m);
let r = (&d).reciprocal();
match r.get_exponent().map(i64::from) {
Some(e) if e < MAX_SETTLED_EXPONENT => {
if float_can_round(r.significand_ref().unwrap(), m - 2, prec, rm) {
return Float::from_float_prec_round(r, prec, rm);
}
}
_ => {
if let Some(result) = reciprocal_of_down_bracket(&d, m, prec, rm) {
return result;
}
}
}
m += increment;
increment = m >> 1;
}
}
pub(crate) fn round_bracket_signed_by(
negative: bool,
lo: Rational,
hi: Rational,
prec: u64,
rm: RoundingMode,
) -> Option<(Float, Ordering)> {
if negative {
round_bracket(&-hi, &-lo, prec, rm)
} else {
round_bracket(&lo, &hi, prec, rm)
}
}
fn tan_rational_tiny(
x: &Rational,
ax: &Rational,
prec: u64,
rm: RoundingMode,
) -> (Float, Ordering) {
let x2 = ax.square();
let mut w = prec + 64;
let mut terms = 2u64;
loop {
let s_lo = sin_bound(ax, w, false);
let s_hi = sin_bound(ax, w, true);
let mut c_lo = Rational::ONE;
let mut term = Rational::ONE;
let mut c_hi = Rational::ONE;
for k in 1..=terms {
term *= &x2;
term /= Rational::from((k << 1) * ((k << 1) - 1));
if k.odd() {
c_lo = &c_hi - &term;
} else {
c_hi = &c_lo + &term;
}
}
let lo = s_lo / &c_hi;
let hi = s_hi / c_lo;
if let Some(result) = round_bracket_signed(x, lo, hi, prec, rm) {
return result;
}
w <<= 1;
terms += 1;
}
}
fn tan_rational_bracket(
x: &Rational,
exp_x: i64,
s: &Float,
c: &Float,
m: u64,
prec: u64,
rm: RoundingMode,
) -> Option<(Float, Ordering)> {
let negative = s.is_sign_negative() != c.is_sign_negative();
if *c == 0u32
|| (c.get_exponent() == Some(Float::MIN_EXPONENT)
&& c.significand_ref().unwrap().is_power_of_2())
{
return Some(overflow(!negative, prec, rm));
}
let (c_lo, c_hi) = nearest_bracket(c, m);
let (s_lo, s_hi) = if *s == 0u32 {
let w = m + 64;
let reduced;
let (y, extra) = if exp_x >= Float::MAX_EXPONENT_I64 {
reduced = reduce_huge(x, exp_x, w);
(&reduced, Some(2 - i64::exact_from(w)))
} else {
(x, None)
};
let exp_y = y.floor_log_base_2_abs() + 1;
let (lo, hi) = trig_rational_near_zero_bracket(y, exp_y, extra, w, m, false);
if lo < 0u32 { (-hi, -lo) } else { (lo, hi) }
} else {
nearest_bracket(s, m)
};
round_bracket_signed_by(negative, s_lo / c_hi, s_hi / c_lo, prec, rm)
}
impl Float {
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn tan_rational_prec_round(x: Rational, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
Self::tan_rational_prec_round_ref(&x, prec, rm)
}
pub fn tan_rational_prec_round_ref(
x: &Rational,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
assert_ne!(prec, 0);
if *x == 0u32 {
return (Self::ZERO, Equal);
}
tan_rational_helper(x, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn tan_rational_prec(x: Rational, prec: u64) -> (Self, Ordering) {
Self::tan_rational_prec_round_ref(&x, prec, Nearest)
}
#[inline]
pub fn tan_rational_prec_ref(x: &Rational, prec: u64) -> (Self, Ordering) {
Self::tan_rational_prec_round_ref(x, prec, Nearest)
}
}
fn tan_turns_special_case(q: &Rational, prec: u64, rm: RoundingMode) -> Option<(Float, Ordering)> {
let d = q.denominator_ref();
if *d > 12u32 {
return None;
}
let d = u64::exact_from(d);
let negative = *q < 0u32;
let n = u64::exact_from(
&Integer::from_sign_and_abs_ref(!negative, q.numerator_ref()).mod_op(Integer::from(d)),
);
match d {
2 | 4 | 8 => Some(match n * (8 / d) {
4 => (
if negative {
Float::ZERO
} else {
Float::NEGATIVE_ZERO
},
Equal,
),
2 => (Float::INFINITY, Equal),
6 => (Float::NEGATIVE_INFINITY, Equal),
1 | 5 => (Float::one_prec(prec), Equal),
_ => (-Float::one_prec(prec), Equal),
}),
_ if rm == Exact => None,
3 | 6 | 12 => Some(match n * (12 / d) {
1 | 7 => signed_constant(Float::sqrt_3_over_3_prec_round, false, prec, rm),
5 | 11 => signed_constant(Float::sqrt_3_over_3_prec_round, true, prec, rm),
2 | 8 => signed_constant(Float::sqrt_3_prec_round, false, prec, rm),
_ => signed_constant(Float::sqrt_3_prec_round, true, prec, rm),
}),
_ => None,
}
}
fn tan_turns_tiny<F: Fn(u64) -> Float>(
scaled: F,
positive: bool,
prec: u64,
rm: RoundingMode,
) -> (Float, Ordering) {
let mut w = prec + prec.ceiling_log_base_2() + 8;
let mut increment = Limb::WIDTH;
loop {
let mut t = scaled(w);
if let Some(result) = scaled_underflow(&t, positive, prec, rm) {
return result;
}
t >>= SCALE;
if float_can_round(t.significand_ref().unwrap(), w - 3, prec, rm) {
return Float::from_float_prec_round(t, prec, rm);
}
w += increment;
increment = w >> 1;
}
}
fn tan_with_period_tiny(xp: &Float, u: u64, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
let u_float = Float::from(u);
let xs = xp << SCALE;
tan_turns_tiny(
|w| {
(Float::pi_prec_round(w, Up).0 << 1u32)
.mul_prec_round_val_ref(&xs, w, Up)
.0
.div_prec_round_val_ref(&u_float, w, Up)
.0
},
*xp > 0u32,
prec,
rm,
)
}
fn tan_turns_tiny_rational(q: &Rational, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
let qs = q << SCALE;
tan_turns_tiny(
|w| {
(Float::pi_prec_round(w, Up).0 << 1u32)
.mul_prec_round(Float::from_rational_prec_round_ref(&qs, w, Up).0, w, Up)
.0
},
*q > 0u32,
prec,
rm,
)
}
fn tan_turns_bracket<F: Fn() -> Rational>(
q: F,
s: &Float,
c: &Float,
m: u64,
prec: u64,
rm: RoundingMode,
) -> Option<(Float, Ordering)> {
let negative = s.is_sign_negative() != c.is_sign_negative();
if *c == 0u32
|| (c.get_exponent() == Some(Float::MIN_EXPONENT)
&& c.significand_ref().unwrap().is_power_of_2())
{
return Some(overflow(!negative, prec, rm));
}
let (c_lo, c_hi) = nearest_bracket(c, m);
let (s_lo, s_hi) = if *s == 0u32 {
let (lo, hi) = trig_turns_near_zero_bracket(&q(), m, false)?;
if lo < 0u32 { (-hi, -lo) } else { (lo, hi) }
} else {
nearest_bracket(s, m)
};
round_bracket_signed_by(negative, s_lo / c_hi, s_hi / c_lo, prec, rm)
}
fn tan_turns_helper(q: &Rational, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
let exp_q = q.floor_log_base_2_abs() + 1;
if exp_q >= -4
&& let Some(result) = tan_turns_special_case(q, prec, rm)
{
return result;
}
assert_ne!(rm, Exact, "Inexact tan_with_period");
if exp_q + 3 <= SCALED_INPUT_EXPONENT {
return tan_turns_tiny_rational(q, prec, rm);
}
let mut m = prec + prec.ceiling_log_base_2() + 13;
let mut increment = Limb::WIDTH;
loop {
let (s, c, _, _) = sin_cos_turns_helper(q, m, Nearest);
let t = if s == 0u32 || c == 0u32 {
None
} else {
Some(s.div_prec_ref_ref(&c, m).0)
};
let exp_t = t.as_ref().and_then(Float::get_exponent).map(i64::from);
match exp_t {
Some(e) if e > MIN_SETTLED_EXPONENT && e < MAX_SETTLED_EXPONENT => {
let t = t.unwrap();
if float_can_round(t.significand_ref().unwrap(), m - 2, prec, rm) {
return Float::from_float_prec_round(t, prec, rm);
}
}
_ => {
if let Some(result) = tan_turns_bracket(|| q.clone(), &s, &c, m, prec, rm) {
return result;
}
}
}
m += increment;
increment = m >> 1;
}
}
fn tan_with_period_prec_round_normal_ref(
x: &Float,
u: u64,
prec: u64,
rm: RoundingMode,
) -> (Float, Ordering) {
let xr;
let xp = if x.lt_abs(&u) {
x
} else {
let p = i64::exact_from(x.get_prec().unwrap()) - i64::from(x.get_exponent().unwrap());
let (r, o) =
x.rem_unsigned_prec_round_ref(u, u64::WIDTH + u64::exact_from(max(p, 0)), Exact);
assert_eq!(o, Equal);
if r == 0u32 {
return (
if *x < 0u32 {
Float::NEGATIVE_ZERO
} else {
Float::ZERO
},
Equal,
);
}
xr = r;
&xr
};
let exp_x = i64::from(xp.get_exponent().unwrap());
if exp_x >= i64::exact_from(u.significant_bits()) - 4
&& let Some(result) =
tan_turns_special_case(&(Rational::exact_from(xp) / Rational::from(u)), prec, rm)
{
return result;
}
assert_ne!(rm, Exact, "Inexact tan_with_period");
let log2u = if u == 1 {
0
} else {
i64::exact_from(u.ceiling_log_base_2()) - 1
};
if exp_x + 3 - log2u <= SCALED_INPUT_EXPONENT {
return tan_with_period_tiny(xp, u, prec, rm);
}
let mut m = prec + prec.ceiling_log_base_2() + 13;
let mut increment = Limb::WIDTH;
loop {
let (s, c, _, _) = sin_cos_with_period_prec_round_normal_ref(xp, u, m, Nearest);
let q = if s == 0u32 || c == 0u32 {
None
} else {
Some(s.div_prec_ref_ref(&c, m).0)
};
let exp_q = q.as_ref().and_then(Float::get_exponent).map(i64::from);
match exp_q {
Some(e) if e > MIN_SETTLED_EXPONENT && e < MAX_SETTLED_EXPONENT => {
let q = q.unwrap();
if float_can_round(q.significand_ref().unwrap(), m - 2, prec, rm) {
return Float::from_float_prec_round(q, prec, rm);
}
}
_ => {
if let Some(result) = tan_turns_bracket(
|| Rational::exact_from(xp) / Rational::from(u),
&s,
&c,
m,
prec,
rm,
) {
return result;
}
}
}
m += increment;
increment = m >> 1;
}
}
impl Float {
#[inline]
pub fn tan_with_period_prec_round(
self,
u: u64,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
self.tan_with_period_prec_round_ref(u, prec, rm)
}
pub fn tan_with_period_prec_round_ref(
&self,
u: u64,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
assert_ne!(prec, 0);
match &self.0 {
_ if u == 0 => (Self::NAN, Equal),
NaN | Infinity { .. } => (Self::NAN, Equal),
Zero { .. } => (self.clone(), Equal),
Finite { .. } => tan_with_period_prec_round_normal_ref(self, u, prec, rm),
}
}
#[inline]
pub fn tan_with_period_prec(self, u: u64, prec: u64) -> (Self, Ordering) {
self.tan_with_period_prec_round(u, prec, Nearest)
}
#[inline]
pub fn tan_with_period_prec_ref(&self, u: u64, prec: u64) -> (Self, Ordering) {
self.tan_with_period_prec_round_ref(u, prec, Nearest)
}
#[inline]
pub fn tan_with_period_round(self, u: u64, rm: RoundingMode) -> (Self, Ordering) {
let prec = self.significant_bits();
self.tan_with_period_prec_round(u, prec, rm)
}
#[inline]
pub fn tan_with_period_round_ref(&self, u: u64, rm: RoundingMode) -> (Self, Ordering) {
self.tan_with_period_prec_round_ref(u, self.significant_bits(), rm)
}
#[inline]
pub fn tan_with_period(self, u: u64) -> Self {
let prec = self.significant_bits();
self.tan_with_period_prec(u, prec).0
}
#[inline]
pub fn tan_with_period_ref(&self, u: u64) -> Self {
self.tan_with_period_prec_ref(u, self.significant_bits()).0
}
#[inline]
pub fn tan_with_period_prec_round_assign(
&mut self,
u: u64,
prec: u64,
rm: RoundingMode,
) -> Ordering {
let (t, o) = self.tan_with_period_prec_round_ref(u, prec, rm);
*self = t;
o
}
#[inline]
pub fn tan_with_period_prec_assign(&mut self, u: u64, prec: u64) -> Ordering {
self.tan_with_period_prec_round_assign(u, prec, Nearest)
}
#[inline]
pub fn tan_with_period_round_assign(&mut self, u: u64, rm: RoundingMode) -> Ordering {
let prec = self.significant_bits();
self.tan_with_period_prec_round_assign(u, prec, rm)
}
#[inline]
pub fn tan_with_period_assign(&mut self, u: u64) {
let prec = self.significant_bits();
self.tan_with_period_prec_assign(u, prec);
}
}
impl Float {
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn tan_with_period_rational_prec_round(
x: Rational,
u: u64,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
Self::tan_with_period_rational_prec_round_ref(&x, u, prec, rm)
}
pub fn tan_with_period_rational_prec_round_ref(
x: &Rational,
u: u64,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
assert_ne!(prec, 0);
if u == 0 {
return (Self::NAN, Equal);
}
if *x == 0u32 {
return (Self::ZERO, Equal);
}
let q = x / Rational::from(u) % Rational::ONE;
if q == 0u32 {
return (
if *x < 0u32 {
Self::NEGATIVE_ZERO
} else {
Self::ZERO
},
Equal,
);
}
tan_turns_helper(&q, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn tan_with_period_rational_prec(x: Rational, u: u64, prec: u64) -> (Self, Ordering) {
Self::tan_with_period_rational_prec_round_ref(&x, u, prec, Nearest)
}
#[inline]
pub fn tan_with_period_rational_prec_ref(x: &Rational, u: u64, prec: u64) -> (Self, Ordering) {
Self::tan_with_period_rational_prec_round_ref(x, u, prec, Nearest)
}
#[inline]
pub fn tan_pi_prec_round(self, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
self.tan_with_period_prec_round(2, prec, rm)
}
#[inline]
pub fn tan_pi_prec_round_ref(&self, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
self.tan_with_period_prec_round_ref(2, prec, rm)
}
#[inline]
pub fn tan_pi_prec(self, prec: u64) -> (Self, Ordering) {
self.tan_with_period_prec(2, prec)
}
#[inline]
pub fn tan_pi_prec_ref(&self, prec: u64) -> (Self, Ordering) {
self.tan_with_period_prec_ref(2, prec)
}
#[inline]
pub fn tan_pi_round(self, rm: RoundingMode) -> (Self, Ordering) {
self.tan_with_period_round(2, rm)
}
#[inline]
pub fn tan_pi_round_ref(&self, rm: RoundingMode) -> (Self, Ordering) {
self.tan_with_period_round_ref(2, rm)
}
#[inline]
pub fn tan_pi(self) -> Self {
let prec = self.significant_bits();
self.tan_pi_prec(prec).0
}
#[inline]
pub fn tan_pi_ref(&self) -> Self {
self.tan_pi_prec_ref(self.significant_bits()).0
}
#[inline]
pub fn tan_pi_prec_round_assign(&mut self, prec: u64, rm: RoundingMode) -> Ordering {
self.tan_with_period_prec_round_assign(2, prec, rm)
}
#[inline]
pub fn tan_pi_prec_assign(&mut self, prec: u64) -> Ordering {
self.tan_with_period_prec_assign(2, prec)
}
#[inline]
pub fn tan_pi_round_assign(&mut self, rm: RoundingMode) -> Ordering {
self.tan_with_period_round_assign(2, rm)
}
#[inline]
pub fn tan_pi_assign(&mut self) {
let prec = self.significant_bits();
self.tan_pi_prec_assign(prec);
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn tan_pi_rational_prec_round(
x: Rational,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
Self::tan_with_period_rational_prec_round_ref(&x, 2, prec, rm)
}
#[inline]
pub fn tan_pi_rational_prec_round_ref(
x: &Rational,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
Self::tan_with_period_rational_prec_round_ref(x, 2, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn tan_pi_rational_prec(x: Rational, prec: u64) -> (Self, Ordering) {
Self::tan_with_period_rational_prec_ref(&x, 2, prec)
}
#[inline]
pub fn tan_pi_rational_prec_ref(x: &Rational, prec: u64) -> (Self, Ordering) {
Self::tan_with_period_rational_prec_ref(x, 2, prec)
}
}
impl Tan for Float {
type Output = Self;
#[inline]
fn tan(self) -> Self {
let prec = self.significant_bits();
self.tan_prec_round(prec, Nearest).0
}
}
impl Tan for &Float {
type Output = Float;
#[inline]
fn tan(self) -> Float {
self.tan_prec_round_ref(self.significant_bits(), Nearest).0
}
}
impl TanAssign for Float {
#[inline]
fn tan_assign(&mut self) {
let prec = self.significant_bits();
self.tan_prec_round_assign(prec, Nearest);
}
}
#[inline]
#[allow(clippy::type_repetition_in_bounds)]
pub fn primitive_float_tan<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::tan_prec, x)
}
#[inline]
#[allow(clippy::type_repetition_in_bounds)]
pub fn primitive_float_tan_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::tan_rational_prec_ref, x)
}
#[inline]
#[allow(clippy::type_repetition_in_bounds)]
pub fn primitive_float_tan_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::tan_with_period_prec(x, u, prec), x)
}
#[inline]
#[allow(clippy::type_repetition_in_bounds)]
pub fn primitive_float_tan_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::tan_with_period_rational_prec_ref(x, u, prec),
x,
)
}
#[inline]
#[allow(clippy::type_repetition_in_bounds)]
pub fn primitive_float_tan_pi<T: PrimitiveFloat>(x: T) -> T
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
primitive_float_tan_with_period(x, 2)
}
#[inline]
#[allow(clippy::type_repetition_in_bounds)]
pub fn primitive_float_tan_pi_rational<T: PrimitiveFloat>(x: &Rational) -> T
where
Float: PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
primitive_float_tan_with_period_rational(x, 2)
}