malachite_float/float/arithmetic/sin_cos.rs
1// Copyright © 2026 Mikhail Hogrefe
2//
3// Uses code adopted from the GNU MPFR Library.
4//
5// Copyright © 2002-2025 Free Software Foundation, Inc.
6//
7// Contributed by the Pascaline and Caramba projects, INRIA.
8//
9// This file is part of Malachite.
10//
11// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
12// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
13// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
14
15// Port of MPFR's simultaneous sine and cosine. `mpfr_sin_cos` (`sin_cos.c`) reduces an argument
16// with |x| >= 2 modulo 2 pi, takes the cosine of the reduced argument, and derives the sine as
17// ±sqrt(1 - cos^2), all inside one Ziv loop that must certify both results. For precisions at or
18// above `SINCOS_THRESHOLD`, `sin`, `cos`, and `sin_cos` all use the asymptotically fast tier
19// `sin_cos_fast` (`mpfr_sincos_fast`, in the same file): the argument is reduced modulo pi/2 and
20// split into chunks of doubling bit length, each chunk's sine and cosine are summed by binary
21// splitting of the Taylor series in integer arithmetic, and the chunks are combined by the
22// angle-addition formulas.
23
24use crate::InnerFloat::{Finite, Infinity, NaN, Zero};
25use crate::float::arithmetic::cos::{
26 NEAR_ZERO_MIN_CANCEL, cos_rational_helper, cos_rational_tiny, cos_turns_helper,
27 cos_turns_special_case, cos_with_period_prec_round_normal_ref, reduce_huge, round_bracket,
28 trig_near_zero, trig_rational_near_zero, trig_turns_near_zero,
29};
30use crate::float::arithmetic::exp::get_z_2exp;
31use crate::float::arithmetic::round_near_x::float_round_near_x;
32use crate::float::arithmetic::sin::{
33 SCALED_INPUT_EXPONENT, sin_rational_helper, sin_turns_helper, sin_turns_special_case,
34 sin_with_period_prec_round_normal_ref,
35};
36use crate::{Float, emulate_float_to_float_pair_fn, emulate_rational_to_float_pair_fn};
37use alloc::vec;
38use core::cmp::Ordering::{self, Equal};
39use core::cmp::{max, min};
40use core::mem::swap;
41use malachite_base::num::arithmetic::traits::{
42 Abs, CeilingLogBase2, FloorSqrt, IsPowerOf2, NegAssign, Parity, PowerOf2, SinCos, SinCosAssign,
43 Square, UnsignedAbs,
44};
45use malachite_base::num::basic::floats::PrimitiveFloat;
46use malachite_base::num::basic::integers::PrimitiveInt;
47use malachite_base::num::basic::traits::{
48 NaN as NaNTrait, NegativeZero as NegativeZeroTrait, One, Zero as ZeroTrait,
49};
50use malachite_base::num::comparison::traits::{EqAbs, PartialOrdAbs};
51use malachite_base::num::conversion::traits::{ExactFrom, RoundingFrom};
52use malachite_base::num::logic::traits::SignificantBits;
53use malachite_base::rounding_modes::RoundingMode::{self, Ceiling, Down, Exact, Nearest, Up};
54use malachite_base::{fail_on_untested_path, split_into_chunks_mut};
55use malachite_nz::integer::Integer;
56use malachite_nz::natural::arithmetic::float::round::float_can_round;
57use malachite_nz::platform::Limb;
58use malachite_q::Rational;
59
60// The outcome of one iteration of the Ziv loop in `sin_cos_prec_round_normal_ref`.
61enum SinCosStep {
62 // The working precision could not decide both results; retry at a higher one.
63 Retry,
64 // The sine and cosine at the working precision, ready for the final rounding.
65 Done(Float, Float),
66 // The input is within about 2^-cancel of an odd multiple of pi/2, so the cosine is tiny and the
67 // sine is within 2^-2cancel of ±1, with the given sign.
68 NearZeroCos { cancel: u64, sin_negative: bool },
69 // The input is within about 2^-cancel of a nonzero multiple of pi, so the sine is tiny and the
70 // cosine is within 2^-2cancel of ±1, with the given sign.
71 NearZeroSin { cancel: u64, cos_negative: bool },
72}
73
74// One iteration of the Ziv loop at working precision `m`, which the cancellation checks may raise
75// for the next iteration (the caller applies the generic increase on `Retry`).
76fn sin_cos_ziv_step(
77 x: &Float,
78 exp_x: i64,
79 prec: u64,
80 rm: RoundingMode,
81 reduce: bool,
82 m: &mut u64,
83) -> SinCosStep {
84 // A cancellation of this many bits sends a result to the near-zero path, and leaves the other
85 // one within 2^-(prec + 2) of ±1, so that it rounds from ±1 alone.
86 let near_zero_threshold = max(NEAR_ZERO_MIN_CANCEL, (prec >> 1) + 1);
87 let m_i = i64::exact_from(*m);
88 let xr;
89 let xx = if reduce {
90 // As in `mpfr_sin`: reduce x modulo 2 pi to xr, and check that xr is at least 2^(2-m) away
91 // from 0 and from ±pi, which settles the sign of the sine.
92 let c_prec = u64::exact_from(exp_x) + *m - 1;
93 let pi = Float::pi_prec(c_prec).0;
94 xr = x.ieee_remainder_prec_ref_val(&pi << 1u32, *m).0;
95 let c = pi.sub_prec_round((&xr).abs(), c_prec, Down).0;
96 let threshold = 3 - m_i;
97 let xr_small = xr == 0u32 || i64::from(xr.get_exponent().unwrap()) < threshold;
98 let c_small = c == 0u32 || i64::from(c.get_exponent().unwrap()) < threshold;
99 if xr_small || c_small {
100 // x is within 2^(4-m) of a multiple of pi (an even one if xr is small, an odd one if c
101 // is small), so |sin(x)| < 2^(5-m); the near-zero path resolves the sine directly, and
102 // the cosine is then ±1 to within 2^-2cancel.
103 let cancel = *m - 4;
104 return if cancel >= near_zero_threshold {
105 SinCosStep::NearZeroSin {
106 cancel,
107 cos_negative: c_small,
108 }
109 } else {
110 SinCosStep::Retry
111 };
112 }
113 &xr
114 } else {
115 x
116 };
117 // the sign of the sine
118 let sign = *xx < 0u32;
119 // c = cos(xx) rounded toward zero
120 let c = xx.cos_prec_round_ref(*m, Down).0;
121 // If no argument reduction was performed, the error is at most ulp(c), otherwise it is at most
122 // ulp(c) + 2^(2-m). Since |c| < 1, we have ulp(c) <= 2^(-m), thus the error is bounded by
123 // 2^(3-m) in that later case.
124 let exp_c = c.get_exponent().map_or(Float::MIN_EXPONENT_I64, i64::from);
125 // |cos(x)| < 2^bound_exp
126 let bound_exp = if reduce { max(exp_c, 2 - m_i) } else { exp_c } + 1;
127 if bound_exp < 0 && exp_x >= 1 {
128 let cancel = u64::exact_from(-bound_exp);
129 if cancel >= near_zero_threshold {
130 return SinCosStep::NearZeroCos {
131 cancel,
132 sin_negative: sign,
133 };
134 }
135 }
136 let err = if reduce { exp_c + m_i - 3 } else { m_i };
137 if c == 0u32
138 || err <= 0
139 || !float_can_round(c.significand_ref().unwrap(), u64::exact_from(err), prec, rm)
140 {
141 return SinCosStep::Retry;
142 }
143 // s = sqrt(1 - c^2): the square rounds up, so its absolute error is bounded by 2^(5-m) if
144 // reduce, and by 2^(2-m) otherwise; 1 - c^2 rounds to nearest, for 2^(6-m) or 2^(3-m); the
145 // square root, also to nearest, has absolute error 2^(6-m-EXP(s)) or 2^(3-m-EXP(s)).
146 let mut s = Float::ONE.sub_prec(c.square_round_ref(Ceiling).0, *m).0;
147 if s == 0u32 {
148 // 1 - c^2 rounded to zero, so sin(xx)^2 is below 2^-(m + 1): x is near a multiple of pi
149 let cancel = (*m >> 1).saturating_sub(1);
150 if reduce && cancel >= near_zero_threshold {
151 return SinCosStep::NearZeroSin {
152 cancel,
153 cos_negative: c < 0u32,
154 };
155 }
156 fail_on_untested_path("sin_cos_ziv_step, 1 - c^2 rounded to zero");
157 *m = max(*m, x.significant_bits()) << 1;
158 return SinCosStep::Retry;
159 }
160 s.sqrt_prec_assign(*m);
161 let exp_s = i64::from(s.get_exponent().unwrap());
162 // the absolute error on s is at most 2^(err - m)
163 let err = 3 + if reduce { 3 } else { 0 } - exp_s;
164 if sign {
165 s.neg_assign();
166 }
167 // |sin(x)| < 2^bound_exp
168 let bound_exp = max(exp_s, err - m_i) + 1;
169 if reduce && bound_exp < 0 {
170 let cancel = u64::exact_from(-bound_exp);
171 if cancel >= near_zero_threshold {
172 return SinCosStep::NearZeroSin {
173 cancel,
174 cos_negative: c < 0u32,
175 };
176 }
177 }
178 // put the error in the form 2^(EXP(s) - err)
179 let err = exp_s + m_i - err;
180 if err > 0 && float_can_round(s.significand_ref().unwrap(), u64::exact_from(err), prec, rm) {
181 return SinCosStep::Done(s, c);
182 }
183 if err < i64::exact_from(prec) {
184 *m += u64::exact_from(i64::exact_from(prec) - err);
185 }
186 // s is exactly ±1 (its square root rounded to nearest), so the sine is within an ulp of ±1
187 // and the working precision is doubled
188 if exp_s == 1 && s.eq_abs(&1u32) {
189 *m <<= 1;
190 }
191 SinCosStep::Retry
192}
193
194// ±1 rounded to `prec` bits under `rm`, as the value of a function known to lie within 2^(1 - err)
195// of ±1 on the side toward zero, with the ternary value; the negative case reuses the positive one
196// with the rounding mode mirrored.
197fn near_one(err: u64, negative: bool, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
198 let err = min(err, prec + 2);
199 if negative {
200 let (r, o) = float_round_near_x(&Float::ONE, err, false, prec, -rm).unwrap();
201 (-r, o.reverse())
202 } else {
203 float_round_near_x(&Float::ONE, err, false, prec, rm).unwrap()
204 }
205}
206
207// Computes sin(x) and cos(x) for a nonzero `Rational` x, rounded to precision `prec` with rounding
208// mode `rm`. (x = 0 is handled by the caller.) Neither result is ever exactly representable, so
209// `rm` must not be `Exact`.
210//
211// This shares the work of `sin_rational_helper` and `cos_rational_helper`: x is rounded once to a
212// `Float` y_f at a working precision w, both functions of y_f are taken together, and both are
213// bracketed using the Lipschitz bound |f(x) - f(y_f)| <= |x - y_f|, the rounding errors, and, for
214// an x too large to be a `Float`, the error of a single `Rational` reduction modulo 2 pi, which for
215// such an x is the dominant cost. The brackets are rounded in `Rational` arithmetic, and w is
216// raised until both resolve.
217pub(crate) fn sin_cos_rational_helper(
218 x: &Rational,
219 prec: u64,
220 rm: RoundingMode,
221) -> (Float, Float, Ordering, Ordering) {
222 assert_ne!(rm, Exact, "Inexact sin_cos");
223 let exp_x = x.floor_log_base_2_abs() + 1; // the MPFR-style exponent of x
224 // For an x so small that the cosine rounds to 1, both results come cheaply from the separate
225 // paths: the sine from its series (or the underflow rule, or, for a precision beyond 2^31 bits,
226 // the general path), and the cosine from 1.
227 if 1 - (exp_x << 1) > i64::exact_from(prec) {
228 let (s, o_s) = sin_rational_helper(x, prec, rm);
229 let (c, o_c) = cos_rational_tiny(prec, rm);
230 return (s, c, o_s, o_c);
231 }
232 // an x too small to be a `Float` at a precision that does not round its cosine to 1 needs the
233 // series paths of both functions, which is only reachable beyond 2^31 bits of precision
234 if exp_x <= Float::MIN_EXPONENT_I64 {
235 fail_on_untested_path("sin_cos_rational_helper, series paths");
236 let (s, o_s) = sin_rational_helper(x, prec, rm);
237 let (c, o_c) = cos_rational_helper(x, prec, rm);
238 return (s, c, o_s, o_c);
239 }
240 let near_zero_threshold = max(NEAR_ZERO_MIN_CANCEL, (prec >> 1) + 1);
241 let huge = exp_x >= Float::MAX_EXPONENT_I64;
242 let mut w = prec + 10;
243 let mut increment = Limb::WIDTH;
244 loop {
245 let reduced;
246 let (y, extra) = if huge {
247 reduced = reduce_huge(x, exp_x, w);
248 (&reduced, Some(2 - i64::exact_from(w)))
249 } else {
250 (x, None)
251 };
252 if *y == 0u32 {
253 // x is an exact multiple of 2 pi at the working precision; a higher precision breaks
254 // the coincidence
255 fail_on_untested_path("sin_cos_rational_helper, reduced argument is zero");
256 } else {
257 let (y_f, y_o) = Float::from_rational_prec_ref(y, w);
258 if !huge && y_o == Equal {
259 // x is exactly representable at w bits, so its sine and cosine are simply those
260 return sin_cos_prec_round_normal_ref(&y_f, prec, rm);
261 }
262 let (s_f, c_f, _, _) = y_f.sin_cos_round_ref(Nearest);
263 // The exponents of y, s_f, and c_f as `Float`s would have them (a zero result means
264 // complete cancellation).
265 let exp_y = y.floor_log_base_2_abs() + 1;
266 let exp_s = s_f
267 .get_exponent()
268 .map_or(Float::MIN_EXPONENT_I64, i64::from);
269 let exp_c = c_f
270 .get_exponent()
271 .map_or(Float::MIN_EXPONENT_I64, i64::from);
272 let w_i = i64::exact_from(w);
273 // |f(y) - f_f| <= 2^(exp_f - w) (half an ulp, doubled for safety) + |y - y_f| <=
274 // 2^(exp_y - w), plus the reduction error; so |f(y)| < 2^(bound + 2) with bound the
275 // largest of those exponents. Heavy cancellation in either function means y is close to
276 // one of its zeros, which its near-zero path resolves exactly, while the other function
277 // is then within 2^-2cancel of ±1 and rounds from ±1 alone.
278 let error_exp = max(exp_y - w_i, extra.unwrap_or(i64::MIN));
279 let bound_s = max(exp_s, error_exp) + 2;
280 let bound_c = max(exp_c, error_exp) + 2;
281 if bound_s < 0 {
282 let cancel = u64::exact_from(-bound_s);
283 if cancel >= near_zero_threshold {
284 let (s, o_s) = trig_rational_near_zero(y, exp_y, prec, rm, extra, w, false);
285 // 1 - |cos(x)| <= sin(x)^2 / 2 < 2^(2 bound_s - 1)
286 let (c, o_c) = near_one((cancel << 1) + 2, c_f < 0u32, prec, rm);
287 return (s, c, o_s, o_c);
288 }
289 }
290 if bound_c < 0 {
291 let cancel = u64::exact_from(-bound_c);
292 if cancel >= near_zero_threshold {
293 let (c, o_c) = trig_rational_near_zero(y, exp_y, prec, rm, extra, w, true);
294 // 1 - |sin(x)| <= cos(x)^2 < 2^(2 bound_c)
295 let (s, o_s) = near_one((cancel << 1) + 1, s_f < 0u32, prec, rm);
296 return (s, c, o_s, o_c);
297 }
298 }
299 let mut delta_s = Rational::power_of_2(exp_s - w_i) + Rational::power_of_2(exp_y - w_i);
300 let mut delta_c = Rational::power_of_2(exp_c - w_i) + Rational::power_of_2(exp_y - w_i);
301 if let Some(extra) = extra {
302 let e = Rational::power_of_2(extra);
303 delta_s += &e;
304 delta_c += e;
305 }
306 let s = Rational::exact_from(&s_f);
307 let c = Rational::exact_from(&c_f);
308 if let Some((s, o_s)) = round_bracket(&(&s - &delta_s), &(s + delta_s), prec, rm)
309 && let Some((c, o_c)) = round_bracket(&(&c - &delta_c), &(c + delta_c), prec, rm)
310 {
311 return (s, c, o_s, o_c);
312 }
313 }
314 w += increment;
315 increment = w >> 1;
316 }
317}
318
319// ---------- asymptotically fast implementation below (mpfr_sincos_fast) ----------
320
321// At or above this precision, `sin`, `cos`, and `sin_cos` use the binary-splitting tier
322// (`sin_cos_fast`) rather than their basic Ziv loops. Tuned on Apple Silicon with `-g tune_sincos`
323// (see `bin_util/tune.rs`), 2026-09-07: the crossover of the two `sin_cos` tiers on inputs in [1/2,
324// 1), with `sin` alone crossing at about 21800 bits and `cos` alone at about 27900. MPFR tunes the
325// same single threshold on `mpfr_sin_cos` (28990 bits on its arm build, 23323 on x86_64 core2).
326// Beyond the crossover the fast tier leads by only a few percent up to about 300000 bits.
327pub(crate) const SINCOS_THRESHOLD: u64 = 25285;
328
329// Truncates `r` to at most `prec` bits, returning the truncated integer and the number of bits
330// dropped.
331//
332// This is `reduce` from `sin_cos.c`, MPFR 4.2.2.
333fn reduce(r: &Integer, prec: u64) -> (Integer, u64) {
334 let l = r.significant_bits().saturating_sub(prec);
335 (r >> l, l)
336}
337
338// Truncates `s` and `c` by the same number of bits, so that the smaller has at most `prec` bits,
339// returning the number of bits dropped.
340//
341// This is `reduce2` from `sin_cos.c`, MPFR 4.2.2.
342fn reduce2(s: &mut Integer, c: &mut Integer, prec: u64) -> u64 {
343 let l = min(s.significant_bits(), c.significant_bits()).saturating_sub(prec);
344 *s >>= l;
345 *c >>= l;
346 l
347}
348
349const KMAX: usize = 64;
350// three arrays of KMAX entries each
351const SCRATCH_LEN: usize = 3 * KMAX;
352
353// Returns (Q0, S0, C0, m) such that S0/(Q0 2^m) approximates sin(X) with absolute error at most 9
354// 2^-prec, and C0/(Q0 2^m) approximates cos(X) with relative (and so absolute) error at most 9
355// 2^-prec, where 0 <= X = p/2^r <= 1/2.
356//
357// sin(X)/X = sum((-1)^i (p/2^r)^i/(2i+1)!, i = 0..infinity), summed by binary splitting with P(a,b)
358// = (-p)^(b-a), Q(a,b) = (2a)(2a+1) 2^r if a+1 = b (except Q(0,1) = 1) and Q(a,c) Q(c,b) otherwise,
359// and T(a,b) = 1 if a+1 = b and Q(c,b) T(a,c) + P(a,c) T(c,b) otherwise. Since P(a,b) is only
360// needed for b-a = 2^k, only the powers p^(2^k) are computed, and the factor 2^r is not stored in Q
361// but tracked as the returned power of two.
362//
363// This is `sin_bs_aux` from `sin_cos.c`, MPFR 4.2.2. Assumes prec >= 10.
364fn sin_bs_aux(p: &Integer, r: u64, prec: u64) -> (Integer, Integer, Integer, u64) {
365 if *p == 0u32 {
366 // sin(x)/x -> 1
367 fail_on_untested_path("sin_bs_aux, p == 0");
368 return (Integer::ONE, Integer::ONE, Integer::ONE, 0);
369 }
370 // check that X = p/2^r <= 1/2 (MPFR's `mpz_sizeinbase (p, 2) - r <= -1` compares in unsigned
371 // arithmetic, so it never fails; the first chunk can be exactly 1/2)
372 let p_bits = p.significant_bits();
373 assert!(p_bits < r || (p_bits == r && p.unsigned_abs_ref().is_power_of_2()));
374 let r0 = r;
375 // normalize p (non-zero here): p = pp * 2^h, then square
376 let h = p.trailing_zeros().unwrap();
377 let pp = (p >> h).square();
378 // x^2 = (p/2^r0)^2 = pp / 2^r
379 let r = (r - h) << 1;
380 // now p is odd
381 let mut scratch = vec![Integer::ZERO; SCRATCH_LEN];
382 split_into_chunks_mut!(scratch, KMAX, [t, q], ptoj); // ptoj[i] = pp^(2^i)
383 let mut log2_nb_terms = [0u64; KMAX];
384 let mut scratch_i = vec![0i64; SCRATCH_LEN];
385 split_into_chunks_mut!(scratch_i, KMAX, [mult, accu], size_ptoj);
386 let mut alloc = 2usize;
387 // 6*2^r - pp = 6*2^r*(1 - x^2/6)
388 t[0] = (const { Integer::const_from_unsigned(6) } << r) - &pp;
389 q[0] = const { Integer::const_from_unsigned(6) };
390 ptoj[0] = pp.clone();
391 ptoj[1] = (&pp).square();
392 size_ptoj[1] = i64::exact_from(ptoj[1].significant_bits());
393 log2_nb_terms[0] = 1;
394 // already take into account the factor x = p/2^r in sin(x) = x * (...): we have x^3 <
395 // 1/2^mult[0]
396 let pp_s = i64::exact_from(pp.significant_bits());
397 let p_s = i64::exact_from(p.significant_bits());
398 let r_i = i64::exact_from(r);
399 mult[0] = r_i - pp_s + i64::exact_from(r0) - p_s;
400 let prec_i = i64::exact_from(prec);
401 let mut k = 0usize;
402 let mut prec_i_have = mult[0];
403 let mut i = 2u64;
404 while prec_i_have < prec_i {
405 // i is even here. Invariant: Q[0]*Q[1]*...*Q[k] equals (2i-1)!, and we have already summed
406 // the terms of index < i in S[0]/Q[0], ..., S[k]/Q[k].
407 k += 1;
408 if k + 1 >= alloc {
409 // necessarily k + 1 == alloc
410 assert_eq!(k + 1, alloc);
411 alloc += 1;
412 assert!(k + 1 < KMAX);
413 ptoj[k + 1] = (&ptoj[k]).square(); // pp^(2^(k+1))
414 size_ptoj[k + 1] = i64::exact_from(ptoj[k + 1].significant_bits());
415 }
416 // For i even, we have Q[k] = (2i)(2i+1), T[k] = 1, then Q[k+1] = (2i+2)(2i+3), T[k+1] = 1,
417 // which reduces to T[k] = (2i+2)(2i+3) 2^r - pp, Q[k] = (2i)(2i+1)(2i+2)(2i+3).
418 assert!(k < KMAX);
419 log2_nb_terms[k] = 1;
420 let two_i = i << 1;
421 q[k] = Integer::from((two_i + 2) * (two_i + 3));
422 t[k] = (&q[k] << r) - &pp;
423 q[k] *= Integer::from(two_i * (two_i + 1));
424 // the next term of the series is divided by Q[k] and multiplied by pp^2/2^(2r), thus the
425 // multiplicative factor is < 1/2^mult[k]
426 mult[k] = i64::exact_from(q[k].significant_bits()) + (r_i << 1) - size_ptoj[1] - 1;
427 // the absolute contribution of the next term is 1/2^accu[k]
428 accu[k] = if k == 0 {
429 mult[k]
430 } else {
431 mult[k] + accu[k - 1]
432 };
433 prec_i_have = accu[k]; // the current term is < 1/2^accu[k]
434 let mut j = (i + 2) >> 1;
435 let mut l = 1usize;
436 while j.even() {
437 // combine and reduce
438 assert!(k >= 1);
439 t[k] *= &ptoj[l];
440 let mut tk1 = &t[k - 1] * &q[k];
441 tk1 <<= r << l;
442 tk1 += &t[k];
443 t[k - 1] = tk1;
444 let qk = q[k].clone();
445 q[k - 1] *= &qk;
446 // the number of terms in S[k-1] is a power of 2 by construction
447 log2_nb_terms[k - 1] += 1;
448 prec_i_have = i64::exact_from(qk.significant_bits());
449 mult[k - 1] += prec_i_have + i64::exact_from(r << l) - size_ptoj[l] - 1;
450 accu[k - 1] = if k == 1 {
451 mult[k - 1]
452 } else {
453 mult[k - 1] + accu[k - 2]
454 };
455 prec_i_have = accu[k - 1];
456 l += 1;
457 j >>= 1;
458 k -= 1;
459 }
460 i += 2;
461 }
462 // Accumulate all products in T[0] and Q[0]. Warning: contrary to above, here we do not have
463 // log2_nb_terms[k-1] = log2_nb_terms[k]+1.
464 let mut h = 0u64; // number of accumulated terms in the right part T[k]/Q[k]
465 while k > 0 {
466 t[k] *= &ptoj[usize::exact_from(log2_nb_terms[k - 1])];
467 let mut tk1 = &t[k - 1] * &q[k];
468 h += u64::power_of_2(log2_nb_terms[k]);
469 tk1 <<= r * h;
470 tk1 += &t[k];
471 t[k - 1] = tk1;
472 let qk = q[k].clone();
473 q[k - 1] *= qk;
474 k -= 1;
475 }
476 // implicit multiplier 2^r for Q0
477 let mut m = i64::exact_from(r0) + r_i * (i64::exact_from(i) - 1);
478 // At this point T[0]/(2^m Q[0]) is an approximation of sin(x) where the first neglected term
479 // has contribution < 1/2^prec; since the series has alternating signs, the error is < 1/2^prec.
480 //
481 // We truncate Q0 to prec bits: the relative error is at most 2^(1-prec), which means that Q0 =
482 // Q[0] (1 + theta) with |theta| <= 2^(1-prec), up to a power of two.
483 let (q0, l) = reduce(&q[0], prec);
484 m += i64::exact_from(l);
485 let (t0, l) = reduce(&t[0], prec);
486 m -= i64::exact_from(l);
487 // multiply by x = p/2^m
488 let (s0, l) = reduce(&(t0 * p), prec); // S0 = T[0] (1 + theta)^2 up to a power of two
489 m -= i64::exact_from(l);
490 // sin(X) ~ S0/Q0 (1 + theta)^3 + err with |theta| <= 2^(1-prec) and |err| <= 2^(-prec), thus
491 // since |S0/Q0| <= 1: |sin(X) - S0/Q0| <= 4 |theta S0/Q0| + |err| <= 9 2^(-prec)
492 //
493 // Compute cos(X) from sin(X): sqrt(1 - (S/Q)^2) = sqrt(Q^2 - S^2)/Q = sqrt(Q0^2 2^(2m) -
494 // S0^2)/Q0. Write S/Q = sin(X) + eps with |eps| <= 9 2^(-prec); then sqrt(Q^2 - S^2) = Q cos(X)
495 // (1 + eps4) with |eps4| <= 9 2^(-prec), since |Q| >= 2^(prec-1) (see sin_cos.c for the steps).
496 // We assume that Q0 2^m >= 2^(prec-1).
497 let m = u64::exact_from(m);
498 assert!(m + q0.significant_bits() >= prec);
499 let c0 = Integer::from(
500 (((&q0).square() << (m << 1)) - (&s0).square())
501 .unsigned_abs()
502 .floor_sqrt(),
503 );
504 (q0, s0, c0, m)
505}
506
507// Returns approximations s and c of sin(x) and cos(x) at precision `prec_s`, and err such that the
508// relative error of each is bounded by 2^err ulps. Assumes 0 < x < pi/4 and prec_s >= 10.
509//
510// This is `sincos_aux` from `sin_cos.c`, MPFR 4.2.2.
511fn sincos_aux(x: &Float, prec_s: u64) -> (Float, Float, u64) {
512 let mut x2 = x.clone(); // exact
513 let mut q_acc = Integer::ONE;
514 let mut l = 0i64;
515 let mut s_acc = Integer::ZERO; // sin(0) = S/(2^l Q), exact
516 let mut c_acc = Integer::ONE; // cos(0) = C/(2^l Q), exact
517 // Invariant: x = X + x2/2^(sh-1), where the part X was already treated, S/(2^l Q) ~ sin(X),
518 // C/(2^l Q) ~ cos(X), and x2/2^(sh-1) < pi/4. sh-1 is the number of already shifted bits in x2.
519 let mut sh = 1u64;
520 let mut j = 0u64;
521 while x2 != 0u32 && sh <= prec_s {
522 let (q2, s2, c2, l2) = if sh > prec_s >> 1 {
523 // sin(x) = x + O(x^3), cos(x) = 1 + O(x^2)
524 let (s2, e) = get_z_2exp(x2.clone()); // S2/2^l2 = x2
525 let mut l2 = -e;
526 l2 += i64::exact_from(sh) - 1;
527 let q2 = Integer::ONE;
528 let c2 = Integer::power_of_2(u64::exact_from(l2));
529 x2 = Float::ZERO;
530 (q2, s2, c2, l2)
531 } else {
532 // y <- trunc(x2 * 2^sh) = trunc(x * 2^(2 sh - 1))
533 x2 <<= sh; // exact
534 // round toward zero: now 0 <= x2 < 2^sh, thus 0 <= x2/2^(sh-1) < 2^(1-sh)
535 let y = Integer::rounding_from(&x2, Down).0;
536 if y == 0u32 {
537 sh <<= 1;
538 j += 1;
539 continue;
540 }
541 let x2_prec = x2.get_prec().unwrap();
542 // should be exact
543 let (d, o) = x2.sub_prec_round(Float::exact_from(&y), x2_prec, Exact);
544 assert_eq!(o, Equal);
545 x2 = d;
546 let (q2, s2, c2, l2) = sin_bs_aux(&y, (sh << 1) - 1, prec_s);
547 // we now have |S2/Q2/2^l2 - sin(X)| <= 9 2^(-prec_s) and |C2/Q2/2^l2 - cos(X)| <= 6
548 // 2^(-prec_s), with X = y/2^(2 sh - 1)
549 (q2, s2, c2, i64::exact_from(l2))
550 };
551 if sh == 1 {
552 // S = 0, C = 1
553 l = l2;
554 q_acc = q2;
555 s_acc = s2;
556 c_acc = c2;
557 } else {
558 // s <- s c2 + c s2, c <- c c2 - s s2, using Karatsuba: a = s + c, b = s2 + c2, t = a b,
559 // d = s s2, e = c c2, s <- t - d - e, c <- e - d
560 let a = &s_acc + &c_acc;
561 let e = c_acc * &c2;
562 let b = c2 + &s2;
563 let d = s2 * &s_acc;
564 let t = a * b;
565 s_acc = t - &d - &e;
566 c_acc = e - d;
567 q_acc *= q2;
568 // after j loops, the error is <= (11j - 2) 2^(prec_s)
569 l += l2;
570 // reduce Q to prec_s bits
571 let (qr, lq) = reduce(&q_acc, prec_s);
572 q_acc = qr;
573 l += i64::exact_from(lq);
574 // reduce S, C to prec_s bits, error <= 11 j 2^(prec_s)
575 l -= i64::exact_from(reduce2(&mut s_acc, &mut c_acc, prec_s));
576 }
577 sh <<= 1;
578 j += 1;
579 }
580 let mut j = 11 * j;
581 let mut err = 0u64;
582 while j > 1 {
583 j = j.div_ceil(2);
584 err += 1;
585 }
586 let q_f = Float::exact_from(&q_acc);
587 let s = Float::from_integer_prec(s_acc, prec_s)
588 .0
589 .div_prec_val_ref(&q_f, prec_s)
590 .0
591 >> l;
592 let c = Float::from_integer_prec(c_acc, prec_s)
593 .0
594 .div_prec(q_f, prec_s)
595 .0
596 >> l;
597 (s, c, err)
598}
599
600// Computes sin(x) and/or cos(x) for a finite nonzero `Float` x, rounded to precision `prec` with
601// rounding mode `rm`, by binary splitting: the argument is reduced modulo pi/2 and split into
602// chunks of doubling bit length, each chunk's sine and cosine are summed by binary splitting of the
603// Taylor series in integer arithmetic, and the chunks are combined by the angle-addition formulas.
604// Only the selected results are rounded and returned.
605//
606// This is `mpfr_sincos_fast` from `sin_cos.c`, MPFR 4.2.2.
607pub(crate) fn sin_cos_fast(
608 x: &Float,
609 prec: u64,
610 rm: RoundingMode,
611 want_sin: bool,
612 want_cos: bool,
613) -> (Option<(Float, Ordering)>, Option<(Float, Ordering)>) {
614 let mut w = prec;
615 w += w.ceiling_log_base_2() + 9; // ensures w >= 10 (needed by sincos_aux)
616 let mut increment = Limb::WIDTH;
617 // 1686629713 / 2^31, just below pi/4
618 let pi_over_4 = const { Float::const_from_unsigned(1686629713) } >> 31u32;
619 let exp_x = i64::from(x.get_exponent().unwrap());
620 loop {
621 let (ts, tc, err) = if *x > 0u32 && *x <= pi_over_4 {
622 // if 0 < x <= pi/4, we can call sincos_aux directly
623 sincos_aux(x, w)
624 } else if *x < 0u32 && *x >= -&pi_over_4 {
625 // if -pi/4 <= x < 0, use sin(-x) = -sin(x)
626 let (ts, tc, err) = sincos_aux(&-x, w);
627 (-ts, tc, err)
628 } else {
629 // argument reduction is needed
630 let pi = Float::pi_prec(if exp_x > 0 {
631 w + u64::exact_from(exp_x)
632 } else {
633 w
634 })
635 .0 >> 1u32; // pi/2
636 // x = q (pi/2 + eps1) + x_red + eps2, where |eps1| <= 1/2 ulp(pi/2) =
637 // 2^(-w-max(0,EXP(x))) and eps2 <= 1/2 ulp(x_red) <= 1/2 ulp(pi/2) = 2^(-w). Since |q|
638 // <= x/(pi/2) <= |x|, we have q |eps1| <= 2^(-w), thus |x - q pi/2 - x_red| <= 2^(1-w).
639 let (mut x_red, _, q) = x.ieee_remainder_and_quotient_bits_prec_ref_ref(&pi, w);
640 // now -pi/4 <= x_red <= pi/4: if x_red < 0, consider -x_red
641 let neg = x_red < 0u32;
642 if neg {
643 x_red.neg_assign();
644 }
645 let (mut ts, mut tc, mut err) = sincos_aux(&x_red, w);
646 err += 1; // to take into account the argument reduction
647 if neg {
648 // sin(-x) = -sin(x), cos(-x) = cos(x)
649 ts.neg_assign();
650 }
651 if q & 2 != 0 {
652 // sin(x + pi) = -sin(x), cos(x + pi) = -cos(x)
653 ts.neg_assign();
654 tc.neg_assign();
655 }
656 if q.odd() {
657 // sin(x + pi/2) = cos(x), cos(x + pi/2) = -sin(x)
658 ts.neg_assign();
659 swap(&mut ts, &mut tc);
660 }
661 (ts, tc, err)
662 };
663 // adjust errors with respect to absolute values
664 let w_i = i64::exact_from(w);
665 let err_i = i64::exact_from(err);
666 let can_round = |t: &Float| {
667 t.get_exponent().is_some_and(|e| {
668 let bits = w_i - (err_i - i64::from(e));
669 bits > 0
670 && float_can_round(
671 t.significand_ref().unwrap(),
672 u64::exact_from(bits),
673 prec,
674 rm,
675 )
676 })
677 };
678 if (!want_sin || can_round(&ts)) && (!want_cos || can_round(&tc)) {
679 return (
680 want_sin.then(|| Float::from_float_prec_round(ts, prec, rm)),
681 want_cos.then(|| Float::from_float_prec_round(tc, prec, rm)),
682 );
683 }
684 w += increment;
685 increment = w >> 1;
686 }
687}
688
689// This is mpfr_sin_cos from sin_cos.c, MPFR 4.2.2, including the `mpfr_sincos_fast` tier for
690// precisions at or above `SINCOS_THRESHOLD`, with the near-zero paths of `sin` and `cos` added for
691// inputs extremely close to a zero of either function. Both results have precision `prec`, where
692// MPFR allows two precisions and works at the larger.
693fn sin_cos_prec_round_normal_ref(
694 x: &Float,
695 prec: u64,
696 rm: RoundingMode,
697) -> (Float, Float, Ordering, Ordering) {
698 assert_ne!(rm, Exact, "Inexact sin_cos");
699 let exp_x = i64::from(x.get_exponent().unwrap());
700 let mut m = prec + prec.ceiling_log_base_2() + 13;
701 // When x is close to 0, say 2^(-k), then there is a cancellation of about 2k bits in
702 // 1-cos(x)^2, and both results may round from x and 1 alone: sin(x) = x - x^3/6 + ... has error
703 // below 2^(3 EXP(x) - 2), and cos(x) = 1 - x^2/2 + ... has error below 2^(2 EXP(x) - 1). MPFR
704 // tries the sine first and then the cosine; here the cosine's bound is the weaker one, and the
705 // reference value 1 always rounds, so it decides.
706 if exp_x < 0 {
707 let neg_two_exp = u64::exact_from(-(exp_x << 1));
708 let err_cos = neg_two_exp + 1;
709 if err_cos > prec + 1
710 && let Some((s, o_s)) =
711 float_round_near_x(x, min(neg_two_exp + 2, prec + 2), false, prec, rm)
712 {
713 let (c, o_c) = near_one(err_cos, false, prec, rm);
714 return (s, c, o_s, o_c);
715 }
716 m += neg_two_exp;
717 }
718 if prec >= SINCOS_THRESHOLD {
719 let (s, c) = sin_cos_fast(x, prec, rm, true, true);
720 let (s, o_s) = s.unwrap();
721 let (c, o_c) = c.unwrap();
722 return (s, c, o_s, o_c);
723 }
724 sin_cos_basic(x, exp_x, m, prec, rm)
725}
726
727// The basic tier of `sin_cos_prec_round_normal_ref`: the Ziv loop of `mpfr_sin_cos` starting at
728// working precision `m`, for a finite nonzero x of exponent `exp_x` that the small-input shortcut
729// did not settle.
730pub(crate) fn sin_cos_basic(
731 x: &Float,
732 exp_x: i64,
733 mut m: u64,
734 prec: u64,
735 rm: RoundingMode,
736) -> (Float, Float, Ordering, Ordering) {
737 let reduce = exp_x >= 2;
738 let mut increment = Limb::WIDTH;
739 loop {
740 match sin_cos_ziv_step(x, exp_x, prec, rm, reduce, &mut m) {
741 SinCosStep::Done(s, c) => {
742 let (s, o_s) = Float::from_float_prec_round(s, prec, rm);
743 let (c, o_c) = Float::from_float_prec_round(c, prec, rm);
744 return (s, c, o_s, o_c);
745 }
746 SinCosStep::NearZeroCos {
747 cancel,
748 sin_negative,
749 } => {
750 // 1 - |sin(x)| <= cos(x)^2 < 2^-2cancel
751 let (c, o_c) = trig_near_zero(x, prec, rm, cancel, true);
752 let (s, o_s) = near_one((cancel << 1) + 1, sin_negative, prec, rm);
753 return (s, c, o_s, o_c);
754 }
755 SinCosStep::NearZeroSin {
756 cancel,
757 cos_negative,
758 } => {
759 // 1 - |cos(x)| <= sin(x)^2 / 2 < 2^-(2cancel + 1)
760 let (s, o_s) = trig_near_zero(x, prec, rm, cancel, false);
761 let (c, o_c) = near_one((cancel << 1) + 2, cos_negative, prec, rm);
762 return (s, c, o_s, o_c);
763 }
764 SinCosStep::Retry => {}
765 }
766 m += increment;
767 increment = m >> 1;
768 }
769}
770
771// One Ziv iteration for the sine and cosine of a fraction of a turn q, given t = 2 pi q (1 +
772// theta)^3 with |theta| <= 2^-w, rounded to w bits. Returns both results when they are settled,
773// either from the values at the working precision or, for a result tiny enough, from the exact
774// near-zero path, with the other then rounded from ±1; returns `None` if the working precision
775// must be raised. `q` produces the exact fraction for the near-zero path, and `sin_near_zero` says
776// whether q is large enough for a tiny sine to mean cancellation rather than a tiny q.
777fn sin_cos_turns_step(
778 t: &Float,
779 w: u64,
780 prec: u64,
781 rm: RoundingMode,
782 sin_near_zero: bool,
783 q: impl Fn() -> Rational,
784) -> Option<(Float, Float, Ordering, Ordering)> {
785 // A cancellation of this many bits sends a result to the near-zero path, and leaves the other
786 // one within 2^-(prec + 2) of ±1, so that it rounds from ±1 alone.
787 let near_zero_threshold = max(NEAR_ZERO_MIN_CANCEL, (prec >> 1) + 1);
788 // since w >= 2, |(1 + theta)^3 - 1| <= 4 theta, so t = 2 pi q + e with |e| <= 2^(EXP(t) + 2 -
789 // w), and both sin and cos move by at most |e|
790 let w_i = i64::exact_from(w);
791 let err_t = i64::from(t.get_exponent().unwrap()) + 2 - w_i;
792 // Both rounded away from zero, so that neither is zero (t is not a multiple of pi/2, being a
793 // nonzero `Float`) and the computed magnitudes bound the true ones.
794 let (s, c, _, _) = t.sin_cos_prec_round_ref(w, Up);
795 let exp_s = i64::from(s.get_exponent().unwrap());
796 let exp_c = i64::from(c.get_exponent().unwrap());
797 // |sin(2 pi q)| <= |s| + |e| < 2^bound_s, and likewise for the cosine
798 let bound_s = max(exp_s, err_t) + 1;
799 let bound_c = max(exp_c, err_t) + 1;
800 // A tiny sine with q not itself tiny means q is close to a multiple of 1/2, and a tiny cosine
801 // means it is close to an odd multiple of 1/4. Either is resolved exactly by the near-zero
802 // path, where the Ziv loop would need its precision raised by the whole cancellation, and the
803 // other function is then within 2^-2cancel of ±1 and rounds from ±1 alone.
804 if bound_s < 0 && sin_near_zero {
805 let cancel = u64::exact_from(-bound_s);
806 if cancel >= near_zero_threshold
807 && let Some((s, o_s)) = trig_turns_near_zero(&q(), prec, rm, false)
808 {
809 // 1 - |cos(2 pi q)| <= sin(2 pi q)^2 / 2 < 2^(2 bound_s - 1)
810 let (c, o_c) = near_one((cancel << 1) + 2, c < 0u32, prec, rm);
811 return Some((s, c, o_s, o_c));
812 }
813 }
814 if bound_c < 0 {
815 let cancel = u64::exact_from(-bound_c);
816 if cancel >= near_zero_threshold
817 && let Some((c, o_c)) = trig_turns_near_zero(&q(), prec, rm, true)
818 {
819 // 1 - |sin(2 pi q)| <= cos(2 pi q)^2 < 2^(2 bound_c)
820 let (s, o_s) = near_one((cancel << 1) + 1, s < 0u32, prec, rm);
821 return Some((s, c, o_s, o_c));
822 }
823 }
824 // The total error on each result is at most |e| + ulp, bounded by 2^(EXP + 1 - w) if err_t <=
825 // EXP - w and by 2^(err_t + 1) otherwise; then normalized for can_round. For the sine, |sin(t)|
826 // <= |t| gives EXP(s) <= EXP(t) + 1, so its ulp is at most 2^err_t / 2 and the second bound
827 // always applies.
828 let err_s = exp_s - err_t - 1;
829 let err_c = exp_c
830 - if err_t <= exp_c - w_i {
831 exp_c - w_i + 1
832 } else {
833 err_t + 1
834 };
835 if err_s > 0
836 && err_c > 0
837 && float_can_round(
838 s.significand_ref().unwrap(),
839 u64::exact_from(err_s),
840 prec,
841 rm,
842 )
843 && float_can_round(
844 c.significand_ref().unwrap(),
845 u64::exact_from(err_c),
846 prec,
847 rm,
848 )
849 {
850 let (s, o_s) = Float::from_float_prec_round(s, prec, rm);
851 let (c, o_c) = Float::from_float_prec_round(c, prec, rm);
852 return Some((s, c, o_s, o_c));
853 }
854 None
855}
856
857// Computes sin(2 pi x/u) and cos(2 pi x/u) for a finite nonzero `Float` x and a nonzero u, rounded
858// to precision `prec` with rounding mode `rm`. `rm` may be `Exact` only when both results are
859// exact, that is, when x/u is a multiple of 1/4.
860//
861// MPFR has no combined function here. This joins the `mpfr_sinu` and `mpfr_cosu` ports (see
862// `sin_with_period_prec_round_normal_ref` and `cos_with_period_prec_round_normal_ref`) around one
863// approximation of 2 pi x/u per Ziv iteration, and one `sin_cos` of it, with the near-zero paths of
864// both.
865pub(crate) fn sin_cos_with_period_prec_round_normal_ref(
866 x: &Float,
867 u: u64,
868 prec: u64,
869 rm: RoundingMode,
870) -> (Float, Float, Ordering, Ordering) {
871 // Range reduction, as in the sine: xr = x mod u, with the sign of x, exactly.
872 let xr;
873 let xp = if x.lt_abs(&u) {
874 x
875 } else {
876 let p = i64::exact_from(x.get_prec().unwrap()) - i64::from(x.get_exponent().unwrap());
877 let (r, o) =
878 x.rem_unsigned_prec_round_ref(u, u64::WIDTH + u64::exact_from(max(p, 0)), Exact);
879 assert_eq!(o, Equal);
880 if r == 0u32 {
881 // x is a multiple of u: the sine is zero, with the sign of x, and the cosine is 1
882 return (
883 if *x < 0u32 {
884 Float::NEGATIVE_ZERO
885 } else {
886 Float::ZERO
887 },
888 Float::one_prec(prec),
889 Equal,
890 Equal,
891 );
892 }
893 xr = r;
894 &xr
895 };
896 // now |xp/u| < 1
897 let exp_x = i64::from(xp.get_exponent().unwrap());
898 // For x/u small, the cosine rounds from 1 alone: |cos(2 pi x/u) - 1| < 2^5 (x/u)^2 <= 2^(5 + 2
899 // EXP(x) - 2 log2u), with u >= 2^log2u, as in the cosine. The sine has no such shortcut, being
900 // close to 2 pi x/u, which must still be computed, so it takes its own path; there is nothing
901 // to share.
902 let log2u = if u == 1 {
903 0
904 } else {
905 i64::exact_from(u.ceiling_log_base_2()) - 1
906 };
907 let err = ((log2u - exp_x) << 1) - 5;
908 if err > 0 {
909 let err = u64::exact_from(err);
910 if err > prec + 1 {
911 // such a small x/u is never a special case, and its cosine is never exact
912 assert_ne!(rm, Exact, "Inexact sin_cos_with_period");
913 let (s, o_s) = sin_with_period_prec_round_normal_ref(xp, u, prec, rm);
914 let (c, o_c) = near_one(err, false, prec, rm);
915 return (s, c, o_s, o_c);
916 }
917 }
918 let u_bits = i64::exact_from(u.significant_bits());
919 // The special cases need |x/u| >= 1/20, so the exponent test skips the `Rational` construction
920 // for the small x that would make it expensive. Only a fraction of a turn with both closed
921 // forms (a multiple of 1/4, or a denominator of 3, 6, 8, or 12) is taken from them; a fifth,
922 // tenth, or twentieth of a turn has only one, and goes through the loop like any other input.
923 if exp_x >= u_bits - 5 {
924 let q = Rational::exact_from(xp) / Rational::from(u);
925 if let Some((s, o_s)) = sin_turns_special_case(&q, prec, rm)
926 && let Some((c, o_c)) = cos_turns_special_case(&q, prec, rm)
927 {
928 return (s, c, o_s, o_c);
929 }
930 }
931 // Only the exact cases can be rounded exactly
932 assert_ne!(rm, Exact, "Inexact sin_cos_with_period");
933 if exp_x <= SCALED_INPUT_EXPONENT {
934 // 2 pi x/u is within a few bits of the bottom of the exponent range, where the sine may
935 // underflow while the cosine has not rounded to 1, which needs a precision beyond 2^31
936 // bits: the separate functions handle each.
937 fail_on_untested_path("sin_cos_with_period_prec_round_normal_ref, tiny x/u");
938 let (s, o_s) = sin_with_period_prec_round_normal_ref(xp, u, prec, rm);
939 let (c, o_c) = cos_with_period_prec_round_normal_ref(xp, u, prec, rm);
940 return (s, c, o_s, o_c);
941 }
942 // For x large, since argument reduction is expensive, we want to avoid any failure in Ziv's
943 // strategy, thus we take into account expx too.
944 let mut prec_t =
945 prec + u64::exact_from(max(exp_x, i64::exact_from(prec.ceiling_log_base_2()))) + 8;
946 let mut increment = Limb::WIDTH;
947 let u_float = Float::from(u);
948 // A tiny sine with x/u not itself tiny means cancellation; for a tiny x/u the sine is simply
949 // close to 2 pi x/u, and its `Rational` form would be expensive.
950 let sin_near_zero = exp_x >= u_bits - 2;
951 loop {
952 // t = 2*pi*x/u * (1 + theta)^3 where |theta| <= 2^-prec_t, from rounding pi, the product,
953 // and the quotient
954 let mut t = Float::pi_prec(prec_t).0 << 1u32;
955 t.mul_prec_assign_ref(xp, prec_t);
956 t.div_prec_assign_ref(&u_float, prec_t);
957 if let Some(result) = sin_cos_turns_step(&t, prec_t, prec, rm, sin_near_zero, || {
958 Rational::exact_from(xp) / Rational::from(u)
959 }) {
960 return result;
961 }
962 prec_t += increment;
963 increment = prec_t >> 1;
964 }
965}
966
967impl Float {
968 /// Computes $\sin x$ and $\cos x$, the sine and cosine of a [`Float`], together, rounding both
969 /// results to the specified precision and with the specified rounding mode. The [`Float`] is
970 /// taken by value. Two [`Ordering`]s are also returned, indicating whether the rounded sine and
971 /// cosine are less than, equal to, or greater than the exact values. Although `NaN`s are not
972 /// comparable to any [`Float`], whenever this function returns a `NaN` it also returns `Equal`
973 /// for it.
974 ///
975 /// The results are the same as those of [`Float::sin_prec_round`] and
976 /// [`Float::cos_prec_round`], but the argument reduction and most of the work are shared, so
977 /// this is faster than the two calls when both values are needed.
978 ///
979 /// See [`RoundingMode`] for a description of the possible rounding modes.
980 ///
981 /// $$
982 /// f(x,p,m) = (\sin x+\varepsilon_s, \cos x+\varepsilon_c).
983 /// $$
984 /// - If $x$ is not finite, $\varepsilon_s$ and $\varepsilon_c$ may be ignored or assumed to be
985 /// 0.
986 /// - If $x$ is finite and $m$ is not `Nearest`, then $|\varepsilon_s| < 2^{\lfloor\log_2 |\sin
987 /// x|\rfloor-p+1}$ and $|\varepsilon_c| < 2^{\lfloor\log_2 |\cos x|\rfloor-p+1}$.
988 /// - If $x$ is finite and $m$ is `Nearest`, then $|\varepsilon_s| \leq 2^{\lfloor\log_2 |\sin
989 /// x|\rfloor-p}$ and $|\varepsilon_c| \leq 2^{\lfloor\log_2 |\cos x|\rfloor-p}$.
990 ///
991 /// If the outputs have a precision, it is `prec`.
992 ///
993 /// Special cases:
994 /// - $f(\text{NaN},p,m)=(\text{NaN},\text{NaN})$
995 /// - $f(\pm\infty,p,m)=(\text{NaN},\text{NaN})$
996 /// - $f(\pm0.0,p,m)=(\pm0.0,1.0)$
997 ///
998 /// Overflow and underflow:
999 /// - Since $|\sin x|\leq 1$ and $|\cos x|\leq 1$, the results never overflow.
1000 /// - Each result underflows exactly as [`Float::sin_prec_round`] or [`Float::cos_prec_round`]
1001 /// does: the sine for an input within $2^{-2^{30}}$ of a nonzero multiple of $\pi$ or of
1002 /// magnitude $2^{-2^{30}}$ rounded toward zero, and the cosine for an input within
1003 /// $2^{-2^{30}}$ of an odd multiple of $\pi/2$, either of which takes more than $2^{30}$ bits
1004 /// of precision. See those functions for the values returned.
1005 ///
1006 /// If you know you'll be using `Nearest`, consider using [`Float::sin_cos_prec`] instead. If
1007 /// you know that your target precision is the precision of the input, consider using
1008 /// [`Float::sin_cos_round`] instead. If both of these things are true, consider using
1009 /// [`Float::sin_cos`] instead.
1010 ///
1011 /// # Worst-case complexity
1012 /// $T(n, m, e) = O(n (\log n)^3 \log\log n + (n+m+e) (\log (n+m+e))^2 \log\log (n+m+e))$
1013 ///
1014 /// $M(n, m, e) = O((n+m+e) \log (n+m+e))$
1015 ///
1016 /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, $m$ is
1017 /// `self.significant_bits()`, and $e$ is the exponent of `self` (0 if `self` has no exponent or
1018 /// a negative one): the sine and cosine at working precision $n$ (for large $n$ by binary
1019 /// splitting of the Taylor series, otherwise the cosine, from which the sine is derived) cost
1020 /// the first term, and for $|x| \geq 2$ the argument is reduced modulo $2\pi$, which requires
1021 /// $\pi$ to about $n + e$ bits and a remainder of the $m$-bit input.
1022 ///
1023 /// # Panics
1024 /// Panics if `rm` is `Exact`, since the sine and cosine of a finite nonzero [`Float`] are never
1025 /// exactly representable, or if `prec` is zero.
1026 ///
1027 /// # Examples
1028 /// ```
1029 /// use malachite_base::rounding_modes::RoundingMode::*;
1030 /// use malachite_float::Float;
1031 /// use std::cmp::Ordering::*;
1032 ///
1033 /// let (s, c, o_s, o_c) = Float::from_unsigned_prec(1u32, 100)
1034 /// .0
1035 /// .sin_cos_prec_round(5, Floor);
1036 /// assert_eq!(s.to_string(), "0.812");
1037 /// assert_eq!(c.to_string(), "0.531");
1038 /// assert_eq!(o_s, Less);
1039 /// assert_eq!(o_c, Less);
1040 ///
1041 /// let (s, c, o_s, o_c) = Float::from_unsigned_prec(1u32, 100)
1042 /// .0
1043 /// .sin_cos_prec_round(5, Ceiling);
1044 /// assert_eq!(s.to_string(), "0.844");
1045 /// assert_eq!(c.to_string(), "0.562");
1046 /// assert_eq!(o_s, Greater);
1047 /// assert_eq!(o_c, Greater);
1048 ///
1049 /// let (s, c, o_s, o_c) = Float::from_unsigned_prec(1u32, 100)
1050 /// .0
1051 /// .sin_cos_prec_round(20, Nearest);
1052 /// assert_eq!(s.to_string(), "0.84147072");
1053 /// assert_eq!(c.to_string(), "0.54030228");
1054 /// assert_eq!(o_s, Less);
1055 /// assert_eq!(o_c, Less);
1056 /// ```
1057 #[inline]
1058 pub fn sin_cos_prec_round(
1059 self,
1060 prec: u64,
1061 rm: RoundingMode,
1062 ) -> (Self, Self, Ordering, Ordering) {
1063 self.sin_cos_prec_round_ref(prec, rm)
1064 }
1065
1066 /// Computes $\sin x$ and $\cos x$, the sine and cosine of a [`Float`], together, rounding both
1067 /// results to the specified precision and with the specified rounding mode. The [`Float`] is
1068 /// taken by reference. Two [`Ordering`]s are also returned, indicating whether the rounded sine
1069 /// and cosine are less than, equal to, or greater than the exact values.
1070 ///
1071 /// See [`Float::sin_cos_prec_round`] for the error bounds, the special cases, overflow and
1072 /// underflow, and the complexity; this function behaves the same way.
1073 ///
1074 /// # Panics
1075 /// Panics if `rm` is `Exact`, since the sine and cosine of a finite nonzero [`Float`] are never
1076 /// exactly representable, or if `prec` is zero.
1077 ///
1078 /// # Examples
1079 /// ```
1080 /// use malachite_base::rounding_modes::RoundingMode::*;
1081 /// use malachite_float::Float;
1082 /// use std::cmp::Ordering::*;
1083 ///
1084 /// let x = Float::from_unsigned_prec(1u32, 100).0;
1085 /// let (s, c, o_s, o_c) = x.sin_cos_prec_round_ref(5, Floor);
1086 /// assert_eq!(s.to_string(), "0.812");
1087 /// assert_eq!(c.to_string(), "0.531");
1088 /// assert_eq!(o_s, Less);
1089 /// assert_eq!(o_c, Less);
1090 ///
1091 /// let (s, c, o_s, o_c) = x.sin_cos_prec_round_ref(20, Nearest);
1092 /// assert_eq!(s.to_string(), "0.84147072");
1093 /// assert_eq!(c.to_string(), "0.54030228");
1094 /// assert_eq!(o_s, Less);
1095 /// assert_eq!(o_c, Less);
1096 /// ```
1097 pub fn sin_cos_prec_round_ref(
1098 &self,
1099 prec: u64,
1100 rm: RoundingMode,
1101 ) -> (Self, Self, Ordering, Ordering) {
1102 assert_ne!(prec, 0);
1103 match &self.0 {
1104 NaN | Infinity { .. } => (Self::NAN, Self::NAN, Equal, Equal),
1105 // sin(±0) = ±0 and cos(±0) = 1, exactly
1106 Zero { .. } => (self.clone(), Self::one_prec(prec), Equal, Equal),
1107 Finite { .. } => sin_cos_prec_round_normal_ref(self, prec, rm),
1108 }
1109 }
1110
1111 /// Computes $\sin x$ and $\cos x$, the sine and cosine of a [`Float`], together, rounding both
1112 /// results to the nearest value of the specified precision. The [`Float`] is taken by value.
1113 /// Two [`Ordering`]s are also returned, indicating whether the rounded sine and cosine are less
1114 /// than, equal to, or greater than the exact values.
1115 ///
1116 /// If a result is equidistant from two [`Float`]s with the specified precision, the [`Float`]
1117 /// with fewer 1s in its binary expansion is chosen. See [`RoundingMode`] for a description of
1118 /// the `Nearest` rounding mode.
1119 ///
1120 /// See [`Float::sin_cos_prec_round`] for the error bounds, the special cases, overflow and
1121 /// underflow, and the complexity; this function behaves the same way with `Nearest`.
1122 ///
1123 /// If you want to use a rounding mode other than `Nearest`, consider using
1124 /// [`Float::sin_cos_prec_round`] instead. If you know that your target precision is the
1125 /// precision of the input, consider using [`Float::sin_cos`] instead.
1126 ///
1127 /// # Panics
1128 /// Panics if `prec` is zero.
1129 ///
1130 /// # Examples
1131 /// ```
1132 /// use malachite_float::Float;
1133 /// use std::cmp::Ordering::*;
1134 ///
1135 /// let (s, c, o_s, o_c) = Float::from_unsigned_prec(1u32, 100).0.sin_cos_prec(5);
1136 /// assert_eq!(s.to_string(), "0.844");
1137 /// assert_eq!(c.to_string(), "0.531");
1138 /// assert_eq!(o_s, Greater);
1139 /// assert_eq!(o_c, Less);
1140 ///
1141 /// let (s, c, o_s, o_c) = Float::from_unsigned_prec(1u32, 100).0.sin_cos_prec(20);
1142 /// assert_eq!(s.to_string(), "0.84147072");
1143 /// assert_eq!(c.to_string(), "0.54030228");
1144 /// assert_eq!(o_s, Less);
1145 /// assert_eq!(o_c, Less);
1146 /// ```
1147 #[inline]
1148 pub fn sin_cos_prec(self, prec: u64) -> (Self, Self, Ordering, Ordering) {
1149 self.sin_cos_prec_round_ref(prec, Nearest)
1150 }
1151
1152 /// Computes $\sin x$ and $\cos x$, the sine and cosine of a [`Float`], together, rounding both
1153 /// results to the nearest value of the specified precision. The [`Float`] is taken by
1154 /// reference. Two [`Ordering`]s are also returned, indicating whether the rounded sine and
1155 /// cosine are less than, equal to, or greater than the exact values.
1156 ///
1157 /// See [`Float::sin_cos_prec`] and [`Float::sin_cos_prec_round`]; this function behaves the
1158 /// same way.
1159 ///
1160 /// # Panics
1161 /// Panics if `prec` is zero.
1162 ///
1163 /// # Examples
1164 /// ```
1165 /// use malachite_float::Float;
1166 /// use std::cmp::Ordering::*;
1167 ///
1168 /// let (s, c, o_s, o_c) = Float::from_unsigned_prec(1u32, 100).0.sin_cos_prec_ref(5);
1169 /// assert_eq!(s.to_string(), "0.844");
1170 /// assert_eq!(c.to_string(), "0.531");
1171 /// assert_eq!(o_s, Greater);
1172 /// assert_eq!(o_c, Less);
1173 /// ```
1174 #[inline]
1175 pub fn sin_cos_prec_ref(&self, prec: u64) -> (Self, Self, Ordering, Ordering) {
1176 self.sin_cos_prec_round_ref(prec, Nearest)
1177 }
1178
1179 /// Computes $\sin x$ and $\cos x$, the sine and cosine of a [`Float`], together, rounding both
1180 /// results to the precision of the input and with the specified rounding mode. The [`Float`] is
1181 /// taken by value. Two [`Ordering`]s are also returned, indicating whether the rounded sine and
1182 /// cosine are less than, equal to, or greater than the exact values.
1183 ///
1184 /// See [`Float::sin_cos_prec_round`] for the error bounds, the special cases, overflow and
1185 /// underflow, and the complexity; this function behaves the same way with `prec` equal to the
1186 /// precision of the input.
1187 ///
1188 /// If you want to specify an output precision, consider using [`Float::sin_cos_prec_round`]
1189 /// instead. If you know you'll be using the `Nearest` rounding mode, consider using
1190 /// [`Float::sin_cos`] instead.
1191 ///
1192 /// # Panics
1193 /// Panics if `rm` is `Exact`, since the sine and cosine of a finite nonzero [`Float`] are never
1194 /// exactly representable.
1195 ///
1196 /// # Examples
1197 /// ```
1198 /// use malachite_base::rounding_modes::RoundingMode::*;
1199 /// use malachite_float::Float;
1200 /// use std::cmp::Ordering::*;
1201 ///
1202 /// let (s, c, o_s, o_c) = Float::from_unsigned_prec(1u32, 5).0.sin_cos_round(Floor);
1203 /// assert_eq!(s.to_string(), "0.812");
1204 /// assert_eq!(c.to_string(), "0.531");
1205 /// assert_eq!(o_s, Less);
1206 /// assert_eq!(o_c, Less);
1207 ///
1208 /// let (s, c, o_s, o_c) = Float::from_unsigned_prec(1u32, 5).0.sin_cos_round(Ceiling);
1209 /// assert_eq!(s.to_string(), "0.844");
1210 /// assert_eq!(c.to_string(), "0.562");
1211 /// assert_eq!(o_s, Greater);
1212 /// assert_eq!(o_c, Greater);
1213 /// ```
1214 #[inline]
1215 pub fn sin_cos_round(self, rm: RoundingMode) -> (Self, Self, Ordering, Ordering) {
1216 let prec = self.significant_bits();
1217 self.sin_cos_prec_round_ref(prec, rm)
1218 }
1219
1220 /// Computes $\sin x$ and $\cos x$, the sine and cosine of a [`Float`], together, rounding both
1221 /// results to the precision of the input and with the specified rounding mode. The [`Float`] is
1222 /// taken by reference. Two [`Ordering`]s are also returned, indicating whether the rounded sine
1223 /// and cosine are less than, equal to, or greater than the exact values.
1224 ///
1225 /// See [`Float::sin_cos_round`] and [`Float::sin_cos_prec_round`]; this function behaves the
1226 /// same way.
1227 ///
1228 /// # Panics
1229 /// Panics if `rm` is `Exact`, since the sine and cosine of a finite nonzero [`Float`] are never
1230 /// exactly representable.
1231 ///
1232 /// # Examples
1233 /// ```
1234 /// use malachite_base::rounding_modes::RoundingMode::*;
1235 /// use malachite_float::Float;
1236 /// use std::cmp::Ordering::*;
1237 ///
1238 /// let (s, c, o_s, o_c) = Float::from_unsigned_prec(1u32, 5)
1239 /// .0
1240 /// .sin_cos_round_ref(Floor);
1241 /// assert_eq!(s.to_string(), "0.812");
1242 /// assert_eq!(c.to_string(), "0.531");
1243 /// assert_eq!(o_s, Less);
1244 /// assert_eq!(o_c, Less);
1245 /// ```
1246 #[inline]
1247 pub fn sin_cos_round_ref(&self, rm: RoundingMode) -> (Self, Self, Ordering, Ordering) {
1248 self.sin_cos_prec_round_ref(self.significant_bits(), rm)
1249 }
1250
1251 /// Replaces a [`Float`] with its sine and writes its cosine to `cos`, rounding both results to
1252 /// the specified precision and with the specified rounding mode. The previous value of `cos` is
1253 /// discarded. Two [`Ordering`]s are returned, indicating whether the rounded sine and cosine
1254 /// are less than, equal to, or greater than the exact values.
1255 ///
1256 /// See [`Float::sin_cos_prec_round`] for the error bounds, the special cases, overflow and
1257 /// underflow, and the complexity; this function behaves the same way.
1258 ///
1259 /// If you know you'll be using `Nearest`, consider using [`Float::sin_cos_prec_assign`]
1260 /// instead. If you know that your target precision is the precision of the input, consider
1261 /// using [`Float::sin_cos_round_assign`] instead. If both of these things are true, consider
1262 /// using [`Float::sin_cos_assign`] instead.
1263 ///
1264 /// # Panics
1265 /// Panics if `rm` is `Exact`, since the sine and cosine of a finite nonzero [`Float`] are never
1266 /// exactly representable, or if `prec` is zero.
1267 ///
1268 /// # Examples
1269 /// ```
1270 /// use malachite_base::num::basic::traits::NaN;
1271 /// use malachite_base::rounding_modes::RoundingMode::*;
1272 /// use malachite_float::Float;
1273 /// use std::cmp::Ordering::*;
1274 ///
1275 /// let mut x = Float::from_unsigned_prec(1u32, 100).0;
1276 /// let mut c = Float::NAN;
1277 /// assert_eq!(x.sin_cos_prec_round_assign(&mut c, 5, Floor), (Less, Less));
1278 /// assert_eq!(x.to_string(), "0.812");
1279 /// assert_eq!(c.to_string(), "0.531");
1280 /// ```
1281 #[inline]
1282 pub fn sin_cos_prec_round_assign(
1283 &mut self,
1284 cos: &mut Self,
1285 prec: u64,
1286 rm: RoundingMode,
1287 ) -> (Ordering, Ordering) {
1288 let (s, c, o_s, o_c) = self.sin_cos_prec_round_ref(prec, rm);
1289 *self = s;
1290 *cos = c;
1291 (o_s, o_c)
1292 }
1293
1294 /// Replaces a [`Float`] with its sine and writes its cosine to `cos`, rounding both results to
1295 /// the nearest value of the specified precision. The previous value of `cos` is discarded. Two
1296 /// [`Ordering`]s are returned, indicating whether the rounded sine and cosine are less than,
1297 /// equal to, or greater than the exact values.
1298 ///
1299 /// See [`Float::sin_cos_prec`] and [`Float::sin_cos_prec_round`]; this function behaves the
1300 /// same way.
1301 ///
1302 /// # Panics
1303 /// Panics if `prec` is zero.
1304 ///
1305 /// # Examples
1306 /// ```
1307 /// use malachite_base::num::basic::traits::NaN;
1308 /// use malachite_float::Float;
1309 /// use std::cmp::Ordering::*;
1310 ///
1311 /// let mut x = Float::from_unsigned_prec(1u32, 100).0;
1312 /// let mut c = Float::NAN;
1313 /// assert_eq!(x.sin_cos_prec_assign(&mut c, 5), (Greater, Less));
1314 /// assert_eq!(x.to_string(), "0.844");
1315 /// assert_eq!(c.to_string(), "0.531");
1316 /// ```
1317 #[inline]
1318 pub fn sin_cos_prec_assign(&mut self, cos: &mut Self, prec: u64) -> (Ordering, Ordering) {
1319 self.sin_cos_prec_round_assign(cos, prec, Nearest)
1320 }
1321
1322 /// Replaces a [`Float`] with its sine and writes its cosine to `cos`, rounding both results to
1323 /// the precision of the input and with the specified rounding mode. The previous value of `cos`
1324 /// is discarded. Two [`Ordering`]s are returned, indicating whether the rounded sine and cosine
1325 /// are less than, equal to, or greater than the exact values.
1326 ///
1327 /// See [`Float::sin_cos_round`] and [`Float::sin_cos_prec_round`]; this function behaves the
1328 /// same way.
1329 ///
1330 /// # Panics
1331 /// Panics if `rm` is `Exact`, since the sine and cosine of a finite nonzero [`Float`] are never
1332 /// exactly representable.
1333 ///
1334 /// # Examples
1335 /// ```
1336 /// use malachite_base::num::basic::traits::NaN;
1337 /// use malachite_base::rounding_modes::RoundingMode::*;
1338 /// use malachite_float::Float;
1339 /// use std::cmp::Ordering::*;
1340 ///
1341 /// let mut x = Float::from_unsigned_prec(1u32, 5).0;
1342 /// let mut c = Float::NAN;
1343 /// assert_eq!(x.sin_cos_round_assign(&mut c, Floor), (Less, Less));
1344 /// assert_eq!(x.to_string(), "0.812");
1345 /// assert_eq!(c.to_string(), "0.531");
1346 /// ```
1347 #[inline]
1348 pub fn sin_cos_round_assign(
1349 &mut self,
1350 cos: &mut Self,
1351 rm: RoundingMode,
1352 ) -> (Ordering, Ordering) {
1353 let prec = self.significant_bits();
1354 self.sin_cos_prec_round_assign(cos, prec, rm)
1355 }
1356}
1357
1358impl Float {
1359 /// Computes $\sin x$ and $\cos x$, the sine and cosine of a [`Rational`], together, rounding
1360 /// both results to the specified precision and with the specified rounding mode, and returning
1361 /// the results as [`Float`]s. The [`Rational`] is taken by value. Two [`Ordering`]s are also
1362 /// returned, indicating whether the rounded sine and cosine are less than, equal to, or greater
1363 /// than the exact values.
1364 ///
1365 /// The results are the same as those of [`Float::sin_rational_prec_round`] and
1366 /// [`Float::cos_rational_prec_round`], but the rounding of the input, the argument reduction,
1367 /// and most of the work are shared, so this is faster than the two calls when both values are
1368 /// needed.
1369 ///
1370 /// See [`RoundingMode`] for a description of the possible rounding modes.
1371 ///
1372 /// $$
1373 /// f(x,p,m) = (\sin x+\varepsilon_s, \cos x+\varepsilon_c).
1374 /// $$
1375 /// - If $m$ is not `Nearest`, then $|\varepsilon_s| < 2^{\lfloor\log_2 |\sin x|\rfloor-p+1}$
1376 /// and $|\varepsilon_c| < 2^{\lfloor\log_2 |\cos x|\rfloor-p+1}$.
1377 /// - If $m$ is `Nearest`, then $|\varepsilon_s| \leq 2^{\lfloor\log_2 |\sin x|\rfloor-p}$ and
1378 /// $|\varepsilon_c| \leq 2^{\lfloor\log_2 |\cos x|\rfloor-p}$.
1379 ///
1380 /// These bounds do not apply when a result underflows.
1381 ///
1382 /// The outputs have precision `prec`.
1383 ///
1384 /// Special cases:
1385 /// - $f(0,p,m)=(0,1)$.
1386 ///
1387 /// Overflow and underflow:
1388 /// - Since $|\sin x|\leq 1$ and $|\cos x|\leq 1$, the results never overflow.
1389 /// - Each result underflows exactly as [`Float::sin_rational_prec_round`] or
1390 /// [`Float::cos_rational_prec_round`] does; see those functions for the inputs concerned and
1391 /// the values returned.
1392 ///
1393 /// If you know you'll be using `Nearest`, consider using [`Float::sin_cos_rational_prec`]
1394 /// instead.
1395 ///
1396 /// # Worst-case complexity
1397 /// $T(n, m, e) = O(n (\log n)^3 \log\log n + (n+m+e) (\log (n+m+e))^2 \log\log (n+m+e))$
1398 ///
1399 /// $M(n, m, e) = O((n+m+e) \log (n+m+e))$
1400 ///
1401 /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, $m$ is `x.significant_bits()`,
1402 /// and $e$ is `x.floor_log_base_2_abs()` (taken as 0 when it is negative or $x = 0$): the input
1403 /// is rounded to a working precision and the [`Float`] sine and cosine taken there together,
1404 /// which for $|x| \geq 2$ reduces the argument modulo $2\pi$ and so needs $\pi$ to about $n +
1405 /// e$ bits.
1406 ///
1407 /// # Panics
1408 /// Panics if `prec` is zero, or if `rm` is `Exact` but the results cannot be represented
1409 /// exactly with the given precision (which is the case for every nonzero input).
1410 ///
1411 /// # Examples
1412 /// ```
1413 /// use malachite_base::rounding_modes::RoundingMode::*;
1414 /// use malachite_float::Float;
1415 /// use malachite_q::Rational;
1416 /// use std::cmp::Ordering::*;
1417 ///
1418 /// let (s, c, o_s, o_c) =
1419 /// Float::sin_cos_rational_prec_round(Rational::from_unsigneds(3u8, 5), 5, Floor);
1420 /// assert_eq!(s.to_string(), "0.562");
1421 /// assert_eq!(c.to_string(), "0.812");
1422 /// assert_eq!(o_s, Less);
1423 /// assert_eq!(o_c, Less);
1424 ///
1425 /// let (s, c, o_s, o_c) =
1426 /// Float::sin_cos_rational_prec_round(Rational::from_unsigneds(3u8, 5), 5, Ceiling);
1427 /// assert_eq!(s.to_string(), "0.594");
1428 /// assert_eq!(c.to_string(), "0.844");
1429 /// assert_eq!(o_s, Greater);
1430 /// assert_eq!(o_c, Greater);
1431 /// ```
1432 #[inline]
1433 #[allow(clippy::needless_pass_by_value)]
1434 pub fn sin_cos_rational_prec_round(
1435 x: Rational,
1436 prec: u64,
1437 rm: RoundingMode,
1438 ) -> (Self, Self, Ordering, Ordering) {
1439 Self::sin_cos_rational_prec_round_ref(&x, prec, rm)
1440 }
1441
1442 /// Computes $\sin x$ and $\cos x$, the sine and cosine of a [`Rational`], together, rounding
1443 /// both results to the specified precision and with the specified rounding mode, and returning
1444 /// the results as [`Float`]s. The [`Rational`] is taken by reference. Two [`Ordering`]s are
1445 /// also returned, indicating whether the rounded sine and cosine are less than, equal to, or
1446 /// greater than the exact values.
1447 ///
1448 /// See [`Float::sin_cos_rational_prec_round`] for the error bounds, the special cases, overflow
1449 /// and underflow, and the complexity; this function behaves the same way.
1450 ///
1451 /// # Panics
1452 /// Panics if `prec` is zero, or if `rm` is `Exact` but the results cannot be represented
1453 /// exactly with the given precision (which is the case for every nonzero input).
1454 ///
1455 /// # Examples
1456 /// ```
1457 /// use malachite_base::rounding_modes::RoundingMode::*;
1458 /// use malachite_float::Float;
1459 /// use malachite_q::Rational;
1460 /// use std::cmp::Ordering::*;
1461 ///
1462 /// let (s, c, o_s, o_c) =
1463 /// Float::sin_cos_rational_prec_round_ref(&Rational::from_unsigneds(3u8, 5), 20, Floor);
1464 /// assert_eq!(s.to_string(), "0.56464195");
1465 /// assert_eq!(c.to_string(), "0.82533550");
1466 /// assert_eq!(o_s, Less);
1467 /// assert_eq!(o_c, Less);
1468 /// ```
1469 pub fn sin_cos_rational_prec_round_ref(
1470 x: &Rational,
1471 prec: u64,
1472 rm: RoundingMode,
1473 ) -> (Self, Self, Ordering, Ordering) {
1474 assert_ne!(prec, 0);
1475 if *x == 0u32 {
1476 // sin(0) = 0 and cos(0) = 1, exactly
1477 return (Self::ZERO, Self::one_prec(prec), Equal, Equal);
1478 }
1479 sin_cos_rational_helper(x, prec, rm)
1480 }
1481
1482 /// Computes $\sin x$ and $\cos x$, the sine and cosine of a [`Rational`], together, rounding
1483 /// both results to the nearest value of the specified precision, and returning the results as
1484 /// [`Float`]s. The [`Rational`] is taken by value. Two [`Ordering`]s are also returned,
1485 /// indicating whether the rounded sine and cosine are less than, equal to, or greater than the
1486 /// exact values.
1487 ///
1488 /// If a result is equidistant from two [`Float`]s with the specified precision, the [`Float`]
1489 /// with fewer 1s in its binary expansion is chosen. See [`RoundingMode`] for a description of
1490 /// the `Nearest` rounding mode.
1491 ///
1492 /// See [`Float::sin_cos_rational_prec_round`] for the error bounds, the special cases, overflow
1493 /// and underflow, and the complexity; this function behaves the same way with `Nearest`.
1494 ///
1495 /// If you want to use a rounding mode other than `Nearest`, consider using
1496 /// [`Float::sin_cos_rational_prec_round`] instead.
1497 ///
1498 /// # Panics
1499 /// Panics if `prec` is zero.
1500 ///
1501 /// # Examples
1502 /// ```
1503 /// use malachite_float::Float;
1504 /// use malachite_q::Rational;
1505 /// use std::cmp::Ordering::*;
1506 ///
1507 /// let (s, c, o_s, o_c) = Float::sin_cos_rational_prec(Rational::from_unsigneds(3u8, 5), 5);
1508 /// assert_eq!(s.to_string(), "0.562");
1509 /// assert_eq!(c.to_string(), "0.812");
1510 /// assert_eq!(o_s, Less);
1511 /// assert_eq!(o_c, Less);
1512 ///
1513 /// let (s, c, o_s, o_c) = Float::sin_cos_rational_prec(Rational::from_unsigneds(3u8, 5), 20);
1514 /// assert_eq!(s.to_string(), "0.56464291");
1515 /// assert_eq!(c.to_string(), "0.82533550");
1516 /// assert_eq!(o_s, Greater);
1517 /// assert_eq!(o_c, Less);
1518 /// ```
1519 #[inline]
1520 #[allow(clippy::needless_pass_by_value)]
1521 pub fn sin_cos_rational_prec(x: Rational, prec: u64) -> (Self, Self, Ordering, Ordering) {
1522 Self::sin_cos_rational_prec_round_ref(&x, prec, Nearest)
1523 }
1524
1525 /// Computes $\sin x$ and $\cos x$, the sine and cosine of a [`Rational`], together, rounding
1526 /// both results to the nearest value of the specified precision, and returning the results as
1527 /// [`Float`]s. The [`Rational`] is taken by reference. Two [`Ordering`]s are also returned,
1528 /// indicating whether the rounded sine and cosine are less than, equal to, or greater than the
1529 /// exact values.
1530 ///
1531 /// See [`Float::sin_cos_rational_prec`] and [`Float::sin_cos_rational_prec_round`]; this
1532 /// function behaves the same way.
1533 ///
1534 /// # Panics
1535 /// Panics if `prec` is zero.
1536 ///
1537 /// # Examples
1538 /// ```
1539 /// use malachite_float::Float;
1540 /// use malachite_q::Rational;
1541 /// use std::cmp::Ordering::*;
1542 ///
1543 /// let (s, c, o_s, o_c) =
1544 /// Float::sin_cos_rational_prec_ref(&Rational::from_unsigneds(3u8, 5), 5);
1545 /// assert_eq!(s.to_string(), "0.562");
1546 /// assert_eq!(c.to_string(), "0.812");
1547 /// assert_eq!(o_s, Less);
1548 /// assert_eq!(o_c, Less);
1549 /// ```
1550 #[inline]
1551 pub fn sin_cos_rational_prec_ref(x: &Rational, prec: u64) -> (Self, Self, Ordering, Ordering) {
1552 Self::sin_cos_rational_prec_round_ref(x, prec, Nearest)
1553 }
1554}
1555
1556// Computes sin(2 pi q) and cos(2 pi q) for a nonzero `Rational` fraction of a turn q in (-1, 1),
1557// rounded to precision `prec` with rounding mode `rm`. `rm` may be `Exact` only when both results
1558// are exact, that is, when q is a multiple of 1/4. This is the `Float` algorithm with the fraction
1559// of a turn taken directly: since q is exact, only pi and the product are rounded.
1560pub(crate) fn sin_cos_turns_helper(
1561 q: &Rational,
1562 prec: u64,
1563 rm: RoundingMode,
1564) -> (Float, Float, Ordering, Ordering) {
1565 let exp_q = q.floor_log_base_2_abs() + 1;
1566 // for q small, the cosine rounds from 1 alone: |cos(2 pi q) - 1| < 1/2 (2 pi q)^2 < 2^(5 + 2
1567 // EXP(q)); the sine takes its own path, as in the `Float` version
1568 let err = -(exp_q << 1) - 5;
1569 if err > 0 {
1570 let err = u64::exact_from(err);
1571 if err > prec + 1 {
1572 assert_ne!(rm, Exact, "Inexact sin_cos_with_period");
1573 let (s, o_s) = sin_turns_helper(q, prec, rm);
1574 let (c, o_c) = near_one(err, false, prec, rm);
1575 return (s, c, o_s, o_c);
1576 }
1577 }
1578 // The special cases need |q| >= 1/20; only a q with both closed forms is taken from them
1579 if exp_q >= -4
1580 && let Some((s, o_s)) = sin_turns_special_case(q, prec, rm)
1581 && let Some((c, o_c)) = cos_turns_special_case(q, prec, rm)
1582 {
1583 return (s, c, o_s, o_c);
1584 }
1585 // Only the exact cases can be rounded exactly
1586 assert_ne!(rm, Exact, "Inexact sin_cos_with_period");
1587 if exp_q <= SCALED_INPUT_EXPONENT {
1588 // as in the `Float` version, only reachable beyond 2^31 bits of precision
1589 fail_on_untested_path("sin_cos_turns_helper, tiny q");
1590 let (s, o_s) = sin_turns_helper(q, prec, rm);
1591 let (c, o_c) = cos_turns_helper(q, prec, rm);
1592 return (s, c, o_s, o_c);
1593 }
1594 let mut w = prec + prec.ceiling_log_base_2() + 8;
1595 let mut increment = Limb::WIDTH;
1596 let sin_near_zero = exp_q >= -2;
1597 loop {
1598 // t = 2*pi*q * (1 + theta)^3 where |theta| <= 2^-w, from rounding q, pi, and the product
1599 let t = (Float::pi_prec(w).0 << 1u32)
1600 .mul_prec(Float::from_rational_prec_ref(q, w).0, w)
1601 .0;
1602 if let Some(result) = sin_cos_turns_step(&t, w, prec, rm, sin_near_zero, || q.clone()) {
1603 return result;
1604 }
1605 w += increment;
1606 increment = w >> 1;
1607 }
1608}
1609
1610impl Float {
1611 /// Computes $\sin(2\pi x/u)$ and $\cos(2\pi x/u)$, the sine and cosine of a [`Float`] measured
1612 /// in $u$ths of a turn, together, rounding both results to the specified precision and with the
1613 /// specified rounding mode. The [`Float`] is taken by value. Two [`Ordering`]s are also
1614 /// returned, indicating whether the rounded sine and cosine are less than, equal to, or greater
1615 /// than the exact values. Although `NaN`s are not comparable to any [`Float`], whenever this
1616 /// function returns a `NaN` it also returns `Equal` for it.
1617 ///
1618 /// The results are the same as those of [`Float::sin_with_period_prec_round`] and
1619 /// [`Float::cos_with_period_prec_round`], but the argument reduction, the computation of $2\pi
1620 /// x/u$, and most of the work are shared, so this is faster than the two calls when both values
1621 /// are needed.
1622 ///
1623 /// See [`RoundingMode`] for a description of the possible rounding modes.
1624 ///
1625 /// $$
1626 /// f(x,u,p,m) = (\sin(2\pi x/u)+\varepsilon_s, \cos(2\pi x/u)+\varepsilon_c).
1627 /// $$
1628 /// - If $x$ is not finite or $u=0$, $\varepsilon_s$ and $\varepsilon_c$ may be ignored or
1629 /// assumed to be 0.
1630 /// - If $x$ is finite, $u\neq 0$, and $m$ is not `Nearest`, then $|\varepsilon_s| <
1631 /// 2^{\lfloor\log_2 |\sin(2\pi x/u)|\rfloor-p+1}$ and $|\varepsilon_c| < 2^{\lfloor\log_2
1632 /// |\cos(2\pi x/u)|\rfloor-p+1}$.
1633 /// - If $x$ is finite, $u\neq 0$, and $m$ is `Nearest`, then $|\varepsilon_s| \leq
1634 /// 2^{\lfloor\log_2 |\sin(2\pi x/u)|\rfloor-p}$ and $|\varepsilon_c| \leq 2^{\lfloor\log_2
1635 /// |\cos(2\pi x/u)|\rfloor-p}$.
1636 ///
1637 /// If the outputs have a precision, it is `prec`.
1638 ///
1639 /// Special cases:
1640 /// - $f(\text{NaN},u,p,m)=(\text{NaN},\text{NaN})$
1641 /// - $f(\pm\infty,u,p,m)=(\text{NaN},\text{NaN})$
1642 /// - $f(x,0,p,m)=(\text{NaN},\text{NaN})$
1643 /// - $f(\pm0.0,u,p,m)=(\pm0.0,1.0)$
1644 /// - If $x/u$ is a multiple of $1/4$, both results are exact: the sine is $0.0$ with the sign
1645 /// of $x$, $1$, or $-1$, and the cosine is $1$, $0.0$, or $-1$, as for
1646 /// [`Float::sin_with_period_prec_round`] and [`Float::cos_with_period_prec_round`].
1647 ///
1648 /// When $x/u$ in lowest terms has denominator 3, 6, 8, or 12, one result is exactly $\pm1/2$ or
1649 /// both are $\pm\sqrt2/2$, and the other is $\pm\sqrt3/2$; these are computed from a single
1650 /// correctly rounded constant rather than from $\pi$ and a sine and cosine, which is far
1651 /// faster. (A fifth, tenth, or twentieth of a turn has a closed form for only one of the two,
1652 /// and is computed like any other input.)
1653 ///
1654 /// Overflow and underflow:
1655 /// - Since $|\sin(2\pi x/u)|\leq 1$ and $|\cos(2\pi x/u)|\leq 1$, the results never overflow.
1656 /// - Each result underflows exactly as [`Float::sin_with_period_prec_round`] or
1657 /// [`Float::cos_with_period_prec_round`] does: the sine for $x/u$ within $2^{-2^{30}}$ of a
1658 /// multiple of $1/2$ without being one, or for an $x$ so small that $2\pi x/u$ is below
1659 /// $2^{-2^{30}}$, and the cosine for $x/u$ within $2^{-2^{30}}$ of an odd multiple of $1/4$
1660 /// without being one, which takes more than $2^{30}$ bits of precision. See those functions
1661 /// for the values returned.
1662 ///
1663 /// If you know you'll be using `Nearest`, consider using [`Float::sin_cos_with_period_prec`]
1664 /// instead. If you know that your target precision is the precision of the input, consider
1665 /// using [`Float::sin_cos_with_period_round`] instead.
1666 ///
1667 /// # Worst-case complexity
1668 /// $T(n, m, e) = O(n (\log n)^3 \log\log n + (n+m+e) (\log (n+m+e))^2 \log\log (n+m+e))$
1669 ///
1670 /// $M(n, m, e) = O((n+m+e) \log (n+m+e))$
1671 ///
1672 /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, $m$ is
1673 /// `self.significant_bits()`, and $e$ is the exponent of `self` (0 if `self` has no exponent or
1674 /// a negative one): the argument is reduced modulo $u$ exactly, and the sine and cosine of
1675 /// $2\pi x/u$ are then taken together at a working precision of about $n + e$ bits, which needs
1676 /// $\pi$ to that many bits.
1677 ///
1678 /// # Panics
1679 /// Panics if `prec` is zero, or if `rm` is `Exact` but the results cannot be represented
1680 /// exactly with the given precision (which is the case unless $x/u$ is a multiple of $1/4$, or
1681 /// $x$ is zero or not finite, or $u$ is zero).
1682 ///
1683 /// # Examples
1684 /// ```
1685 /// use malachite_base::num::basic::traits::One;
1686 /// use malachite_base::rounding_modes::RoundingMode::*;
1687 /// use malachite_float::Float;
1688 /// use std::cmp::Ordering::*;
1689 ///
1690 /// let (s, c, o_s, o_c) = Float::ONE.sin_cos_with_period_prec_round(7, 10, Floor);
1691 /// assert_eq!(s.to_string(), "0.78125");
1692 /// assert_eq!(c.to_string(), "0.62305");
1693 /// assert_eq!(o_s, Less);
1694 /// assert_eq!(o_c, Less);
1695 ///
1696 /// let (s, c, o_s, o_c) = Float::ONE.sin_cos_with_period_prec_round(7, 10, Ceiling);
1697 /// assert_eq!(s.to_string(), "0.78223");
1698 /// assert_eq!(c.to_string(), "0.62402");
1699 /// assert_eq!(o_s, Greater);
1700 /// assert_eq!(o_c, Greater);
1701 ///
1702 /// let (s, c, o_s, o_c) = Float::ONE.sin_cos_with_period_prec_round(7, 10, Nearest);
1703 /// assert_eq!(s.to_string(), "0.78223");
1704 /// assert_eq!(c.to_string(), "0.62305");
1705 /// assert_eq!(o_s, Greater);
1706 /// assert_eq!(o_c, Less);
1707 ///
1708 /// // a quarter turn is exact
1709 /// let (s, c, o_s, o_c) = Float::from(90u32).sin_cos_with_period_prec_round(360, 10, Exact);
1710 /// assert_eq!(s.to_string(), "1.0000");
1711 /// assert_eq!(c.to_string(), "0.0");
1712 /// assert_eq!(o_s, Equal);
1713 /// assert_eq!(o_c, Equal);
1714 ///
1715 /// // a twelfth of a turn: 1/2 exactly, and sqrt(3)/2
1716 /// let (s, c, o_s, o_c) = Float::from(30u32).sin_cos_with_period_prec_round(360, 10, Nearest);
1717 /// assert_eq!(s.to_string(), "0.50000");
1718 /// assert_eq!(c.to_string(), "0.86621");
1719 /// assert_eq!(o_s, Equal);
1720 /// assert_eq!(o_c, Greater);
1721 /// ```
1722 #[inline]
1723 pub fn sin_cos_with_period_prec_round(
1724 self,
1725 u: u64,
1726 prec: u64,
1727 rm: RoundingMode,
1728 ) -> (Self, Self, Ordering, Ordering) {
1729 self.sin_cos_with_period_prec_round_ref(u, prec, rm)
1730 }
1731
1732 /// Computes $\sin(2\pi x/u)$ and $\cos(2\pi x/u)$, the sine and cosine of a [`Float`] measured
1733 /// in $u$ths of a turn, together, rounding both results to the specified precision and with the
1734 /// specified rounding mode. The [`Float`] is taken by reference. Two [`Ordering`]s are also
1735 /// returned, indicating whether the rounded sine and cosine are less than, equal to, or greater
1736 /// than the exact values. Although `NaN`s are not comparable to any [`Float`], whenever this
1737 /// function returns a `NaN` it also returns `Equal` for it.
1738 ///
1739 /// See [`Float::sin_cos_with_period_prec_round`] for the error bounds, the special cases,
1740 /// overflow and underflow, and the complexity; this function behaves the same way.
1741 ///
1742 /// # Panics
1743 /// Panics if `prec` is zero, or if `rm` is `Exact` but the results cannot be represented
1744 /// exactly with the given precision (which is the case unless $x/u$ is a multiple of $1/4$, or
1745 /// $x$ is zero or not finite, or $u$ is zero).
1746 ///
1747 /// # Examples
1748 /// ```
1749 /// use malachite_base::num::basic::traits::One;
1750 /// use malachite_base::rounding_modes::RoundingMode::*;
1751 /// use malachite_float::Float;
1752 /// use std::cmp::Ordering::*;
1753 ///
1754 /// let (s, c, o_s, o_c) = Float::ONE.sin_cos_with_period_prec_round_ref(7, 10, Floor);
1755 /// assert_eq!(s.to_string(), "0.78125");
1756 /// assert_eq!(c.to_string(), "0.62305");
1757 /// assert_eq!(o_s, Less);
1758 /// assert_eq!(o_c, Less);
1759 ///
1760 /// let (s, c, o_s, o_c) = Float::ONE.sin_cos_with_period_prec_round_ref(7, 10, Ceiling);
1761 /// assert_eq!(s.to_string(), "0.78223");
1762 /// assert_eq!(c.to_string(), "0.62402");
1763 /// assert_eq!(o_s, Greater);
1764 /// assert_eq!(o_c, Greater);
1765 /// ```
1766 pub fn sin_cos_with_period_prec_round_ref(
1767 &self,
1768 u: u64,
1769 prec: u64,
1770 rm: RoundingMode,
1771 ) -> (Self, Self, Ordering, Ordering) {
1772 assert_ne!(prec, 0);
1773 match &self.0 {
1774 // for u=0, return NaN
1775 _ if u == 0 => (Self::NAN, Self::NAN, Equal, Equal),
1776 NaN | Infinity { .. } => (Self::NAN, Self::NAN, Equal, Equal),
1777 // x is zero: sin(±0) = ±0 and cos(±0) = 1
1778 Zero { .. } => (self.clone(), Self::one_prec(prec), Equal, Equal),
1779 Finite { .. } => sin_cos_with_period_prec_round_normal_ref(self, u, prec, rm),
1780 }
1781 }
1782
1783 /// Computes $\sin(2\pi x/u)$ and $\cos(2\pi x/u)$, the sine and cosine of a [`Float`] measured
1784 /// in $u$ths of a turn, together, rounding both results to the nearest value of the specified
1785 /// precision. The [`Float`] is taken by value. Two [`Ordering`]s are also returned, indicating
1786 /// whether the rounded sine and cosine are less than, equal to, or greater than the exact
1787 /// values. Although `NaN`s are not comparable to any [`Float`], whenever this function returns
1788 /// a `NaN` it also returns `Equal` for it.
1789 ///
1790 /// If a result is equidistant from two [`Float`]s with the specified precision, the [`Float`]
1791 /// with fewer 1s in its binary expansion is chosen. See [`RoundingMode`] for a description of
1792 /// the `Nearest` rounding mode.
1793 ///
1794 /// See [`Float::sin_cos_with_period_prec_round`] for the error bounds, the special cases,
1795 /// overflow and underflow, and the complexity; this function behaves the same way with
1796 /// `Nearest`.
1797 ///
1798 /// If you want to use a rounding mode other than `Nearest`, consider using
1799 /// [`Float::sin_cos_with_period_prec_round`] instead. If you know that your target precision is
1800 /// the precision of the input, consider using [`Float::sin_cos_with_period_round`] with
1801 /// `Nearest` instead.
1802 ///
1803 /// # Panics
1804 /// Panics if `prec` is zero.
1805 ///
1806 /// # Examples
1807 /// ```
1808 /// use malachite_base::num::basic::traits::One;
1809 /// use malachite_float::Float;
1810 /// use std::cmp::Ordering::*;
1811 ///
1812 /// let (s, c, o_s, o_c) = Float::ONE.sin_cos_with_period_prec(7, 10);
1813 /// assert_eq!(s.to_string(), "0.78223");
1814 /// assert_eq!(c.to_string(), "0.62305");
1815 /// assert_eq!(o_s, Greater);
1816 /// assert_eq!(o_c, Less);
1817 ///
1818 /// let (s, c, o_s, o_c) = Float::ONE.sin_cos_with_period_prec(360, 53);
1819 /// assert_eq!(s.to_string(), "0.017452406437283512");
1820 /// assert_eq!(c.to_string(), "0.99984769515639127");
1821 /// assert_eq!(o_s, Less);
1822 /// assert_eq!(o_c, Greater);
1823 ///
1824 /// // an eighth of a turn: sqrt(2)/2 for both
1825 /// let (s, c, o_s, o_c) = Float::ONE.sin_cos_with_period_prec(8, 10);
1826 /// assert_eq!(s.to_string(), "0.70703");
1827 /// assert_eq!(c.to_string(), "0.70703");
1828 /// assert_eq!(o_s, Less);
1829 /// assert_eq!(o_c, Less);
1830 /// ```
1831 #[inline]
1832 pub fn sin_cos_with_period_prec(self, u: u64, prec: u64) -> (Self, Self, Ordering, Ordering) {
1833 self.sin_cos_with_period_prec_round_ref(u, prec, Nearest)
1834 }
1835
1836 /// Computes $\sin(2\pi x/u)$ and $\cos(2\pi x/u)$, the sine and cosine of a [`Float`] measured
1837 /// in $u$ths of a turn, together, rounding both results to the nearest value of the specified
1838 /// precision. The [`Float`] is taken by reference. Two [`Ordering`]s are also returned,
1839 /// indicating whether the rounded sine and cosine are less than, equal to, or greater than the
1840 /// exact values. Although `NaN`s are not comparable to any [`Float`], whenever this function
1841 /// returns a `NaN` it also returns `Equal` for it.
1842 ///
1843 /// See [`Float::sin_cos_with_period_prec`] and [`Float::sin_cos_with_period_prec_round`]; this
1844 /// function behaves the same way.
1845 ///
1846 /// # Panics
1847 /// Panics if `prec` is zero.
1848 ///
1849 /// # Examples
1850 /// ```
1851 /// use malachite_base::num::basic::traits::One;
1852 /// use malachite_float::Float;
1853 /// use std::cmp::Ordering::*;
1854 ///
1855 /// let (s, c, o_s, o_c) = Float::ONE.sin_cos_with_period_prec_ref(7, 10);
1856 /// assert_eq!(s.to_string(), "0.78223");
1857 /// assert_eq!(c.to_string(), "0.62305");
1858 /// assert_eq!(o_s, Greater);
1859 /// assert_eq!(o_c, Less);
1860 /// ```
1861 #[inline]
1862 pub fn sin_cos_with_period_prec_ref(
1863 &self,
1864 u: u64,
1865 prec: u64,
1866 ) -> (Self, Self, Ordering, Ordering) {
1867 self.sin_cos_with_period_prec_round_ref(u, prec, Nearest)
1868 }
1869
1870 /// Computes $\sin(2\pi x/u)$ and $\cos(2\pi x/u)$, the sine and cosine of a [`Float`] measured
1871 /// in $u$ths of a turn, together, rounding both results to the precision of the input and with
1872 /// the specified rounding mode. The [`Float`] is taken by value. Two [`Ordering`]s are also
1873 /// returned, indicating whether the rounded sine and cosine are less than, equal to, or greater
1874 /// than the exact values. Although `NaN`s are not comparable to any [`Float`], whenever this
1875 /// function returns a `NaN` it also returns `Equal` for it.
1876 ///
1877 /// See [`Float::sin_cos_with_period_prec_round`] for the error bounds, the special cases,
1878 /// overflow and underflow, and the complexity; this function behaves the same way with `prec`
1879 /// equal to the precision of the input.
1880 ///
1881 /// If you want to specify an output precision, consider using
1882 /// [`Float::sin_cos_with_period_prec_round`] instead. If you know you'll be using the `Nearest`
1883 /// rounding mode, consider using [`Float::sin_cos_with_period_prec`] with the precision of the
1884 /// input instead.
1885 ///
1886 /// # Panics
1887 /// Panics if `rm` is `Exact` but the results cannot be represented exactly with the precision
1888 /// of the input (which is the case unless $x/u$ is a multiple of $1/4$, or $x$ is zero or not
1889 /// finite, or $u$ is zero).
1890 ///
1891 /// # Examples
1892 /// ```
1893 /// use malachite_base::rounding_modes::RoundingMode::*;
1894 /// use malachite_float::Float;
1895 /// use std::cmp::Ordering::*;
1896 ///
1897 /// let (s, c, o_s, o_c) = Float::from_unsigned_prec(1u32, 10)
1898 /// .0
1899 /// .sin_cos_with_period_round(7, Floor);
1900 /// assert_eq!(s.to_string(), "0.78125");
1901 /// assert_eq!(c.to_string(), "0.62305");
1902 /// assert_eq!(o_s, Less);
1903 /// assert_eq!(o_c, Less);
1904 ///
1905 /// let (s, c, o_s, o_c) = Float::from_unsigned_prec(1u32, 10)
1906 /// .0
1907 /// .sin_cos_with_period_round(7, Ceiling);
1908 /// assert_eq!(s.to_string(), "0.78223");
1909 /// assert_eq!(c.to_string(), "0.62402");
1910 /// assert_eq!(o_s, Greater);
1911 /// assert_eq!(o_c, Greater);
1912 /// ```
1913 #[inline]
1914 pub fn sin_cos_with_period_round(
1915 self,
1916 u: u64,
1917 rm: RoundingMode,
1918 ) -> (Self, Self, Ordering, Ordering) {
1919 let prec = self.significant_bits();
1920 self.sin_cos_with_period_prec_round_ref(u, prec, rm)
1921 }
1922
1923 /// Computes $\sin(2\pi x/u)$ and $\cos(2\pi x/u)$, the sine and cosine of a [`Float`] measured
1924 /// in $u$ths of a turn, together, rounding both results to the precision of the input and with
1925 /// the specified rounding mode. The [`Float`] is taken by reference. Two [`Ordering`]s are also
1926 /// returned, indicating whether the rounded sine and cosine are less than, equal to, or greater
1927 /// than the exact values. Although `NaN`s are not comparable to any [`Float`], whenever this
1928 /// function returns a `NaN` it also returns `Equal` for it.
1929 ///
1930 /// See [`Float::sin_cos_with_period_round`] and [`Float::sin_cos_with_period_prec_round`]; this
1931 /// function behaves the same way.
1932 ///
1933 /// # Panics
1934 /// Panics if `rm` is `Exact` but the results cannot be represented exactly with the precision
1935 /// of the input (which is the case unless $x/u$ is a multiple of $1/4$, or $x$ is zero or not
1936 /// finite, or $u$ is zero).
1937 ///
1938 /// # Examples
1939 /// ```
1940 /// use malachite_base::rounding_modes::RoundingMode::*;
1941 /// use malachite_float::Float;
1942 /// use std::cmp::Ordering::*;
1943 ///
1944 /// let (s, c, o_s, o_c) = Float::from_unsigned_prec(1u32, 10)
1945 /// .0
1946 /// .sin_cos_with_period_round_ref(7, Floor);
1947 /// assert_eq!(s.to_string(), "0.78125");
1948 /// assert_eq!(c.to_string(), "0.62305");
1949 /// assert_eq!(o_s, Less);
1950 /// assert_eq!(o_c, Less);
1951 /// ```
1952 #[inline]
1953 pub fn sin_cos_with_period_round_ref(
1954 &self,
1955 u: u64,
1956 rm: RoundingMode,
1957 ) -> (Self, Self, Ordering, Ordering) {
1958 self.sin_cos_with_period_prec_round_ref(u, self.significant_bits(), rm)
1959 }
1960
1961 /// Computes $\sin(2\pi x/u)$ and $\cos(2\pi x/u)$, the sine and cosine of a [`Float`] measured
1962 /// in $u$ths of a turn (so that `u = 360` is degrees), together, rounding both results to the
1963 /// precision of the input and to the nearest [`Float`]s. The [`Float`] is taken by value.
1964 ///
1965 /// If either result is equidistant from two [`Float`]s with the precision of the input, the
1966 /// [`Float`] with fewer 1s in its binary expansion is chosen. See [`RoundingMode`] for a
1967 /// description of the `Nearest` rounding mode.
1968 ///
1969 /// See [`Float::sin_cos_with_period_prec_round`] for the error bounds, the special and
1970 /// closed-form cases, overflow and underflow, and the complexity; this function behaves the
1971 /// same way with `prec` equal to the precision of the input and `rm` equal to `Nearest`.
1972 ///
1973 /// If you want to use a rounding mode other than `Nearest`, consider using
1974 /// [`Float::sin_cos_with_period_round`] instead. If you want to specify an output precision,
1975 /// consider using [`Float::sin_cos_with_period_prec`]. If you want both of these things,
1976 /// consider using [`Float::sin_cos_with_period_prec_round`].
1977 ///
1978 /// # Examples
1979 /// ```
1980 /// use malachite_float::Float;
1981 ///
1982 /// let (s, c) = Float::from_unsigned_prec(1u32, 10).0.sin_cos_with_period(7);
1983 /// assert_eq!(s.to_string(), "0.78223");
1984 /// assert_eq!(c.to_string(), "0.62305");
1985 /// ```
1986 #[inline]
1987 pub fn sin_cos_with_period(self, u: u64) -> (Self, Self) {
1988 let prec = self.significant_bits();
1989 let (s, c, _, _) = self.sin_cos_with_period_prec(u, prec);
1990 (s, c)
1991 }
1992
1993 /// Computes $\sin(2\pi x/u)$ and $\cos(2\pi x/u)$, the sine and cosine of a [`Float`] measured
1994 /// in $u$ths of a turn (so that `u = 360` is degrees), together, rounding both results to the
1995 /// precision of the input and to the nearest [`Float`]s. The [`Float`] is taken by reference.
1996 ///
1997 /// If either result is equidistant from two [`Float`]s with the precision of the input, the
1998 /// [`Float`] with fewer 1s in its binary expansion is chosen. See [`RoundingMode`] for a
1999 /// description of the `Nearest` rounding mode.
2000 ///
2001 /// See [`Float::sin_cos_with_period_prec_round`] for the error bounds, the special and
2002 /// closed-form cases, overflow and underflow, and the complexity; this function behaves the
2003 /// same way with `prec` equal to the precision of the input and `rm` equal to `Nearest`.
2004 ///
2005 /// If you want to use a rounding mode other than `Nearest`, consider using
2006 /// [`Float::sin_cos_with_period_round_ref`] instead. If you want to specify an output
2007 /// precision, consider using [`Float::sin_cos_with_period_prec_ref`]. If you want both of these
2008 /// things, consider using [`Float::sin_cos_with_period_prec_round_ref`].
2009 ///
2010 /// # Examples
2011 /// ```
2012 /// use malachite_float::Float;
2013 ///
2014 /// let (s, c) = (&Float::from_unsigned_prec(1u32, 10).0).sin_cos_with_period_ref(7);
2015 /// assert_eq!(s.to_string(), "0.78223");
2016 /// assert_eq!(c.to_string(), "0.62305");
2017 /// ```
2018 #[inline]
2019 pub fn sin_cos_with_period_ref(&self, u: u64) -> (Self, Self) {
2020 let (s, c, _, _) = self.sin_cos_with_period_prec_ref(u, self.significant_bits());
2021 (s, c)
2022 }
2023
2024 /// Replaces a [`Float`] measured in $u$ths of a turn with its sine and writes its cosine to
2025 /// `cos`, rounding both results to the specified precision and with the specified rounding
2026 /// mode. The previous value of `cos` is discarded. Two [`Ordering`]s are returned, indicating
2027 /// whether the rounded sine and cosine are less than, equal to, or greater than the exact
2028 /// values. Although `NaN`s are not comparable to any [`Float`], whenever this function sets a
2029 /// `NaN` it also returns `Equal` for it.
2030 ///
2031 /// See [`Float::sin_cos_with_period_prec_round`] for the error bounds, the special cases,
2032 /// overflow and underflow, and the complexity; this function behaves the same way.
2033 ///
2034 /// If you know you'll be using `Nearest`, consider using
2035 /// [`Float::sin_cos_with_period_prec_assign`] instead. If you know that your target precision
2036 /// is the precision of the input, consider using [`Float::sin_cos_with_period_round_assign`]
2037 /// instead.
2038 ///
2039 /// # Panics
2040 /// Panics if `prec` is zero, or if `rm` is `Exact` but the results cannot be represented
2041 /// exactly with the given precision (which is the case unless $x/u$ is a multiple of $1/4$, or
2042 /// $x$ is zero or not finite, or $u$ is zero).
2043 ///
2044 /// # Examples
2045 /// ```
2046 /// use malachite_base::num::basic::traits::{NaN, One};
2047 /// use malachite_base::rounding_modes::RoundingMode::*;
2048 /// use malachite_float::Float;
2049 /// use std::cmp::Ordering::*;
2050 ///
2051 /// let mut x = Float::ONE;
2052 /// let mut c = Float::NAN;
2053 /// assert_eq!(
2054 /// x.sin_cos_with_period_prec_round_assign(&mut c, 7, 10, Floor),
2055 /// (Less, Less)
2056 /// );
2057 /// assert_eq!(x.to_string(), "0.78125");
2058 /// assert_eq!(c.to_string(), "0.62305");
2059 /// ```
2060 #[inline]
2061 pub fn sin_cos_with_period_prec_round_assign(
2062 &mut self,
2063 cos: &mut Self,
2064 u: u64,
2065 prec: u64,
2066 rm: RoundingMode,
2067 ) -> (Ordering, Ordering) {
2068 let (s, c, o_s, o_c) = self.sin_cos_with_period_prec_round_ref(u, prec, rm);
2069 *self = s;
2070 *cos = c;
2071 (o_s, o_c)
2072 }
2073
2074 /// Replaces a [`Float`] measured in $u$ths of a turn with its sine and writes its cosine to
2075 /// `cos`, rounding both results to the nearest value of the specified precision. The previous
2076 /// value of `cos` is discarded. Two [`Ordering`]s are returned, indicating whether the rounded
2077 /// sine and cosine are less than, equal to, or greater than the exact values. Although `NaN`s
2078 /// are not comparable to any [`Float`], whenever this function sets a `NaN` it also returns
2079 /// `Equal` for it.
2080 ///
2081 /// See [`Float::sin_cos_with_period_prec`] and [`Float::sin_cos_with_period_prec_round`]; this
2082 /// function behaves the same way.
2083 ///
2084 /// # Panics
2085 /// Panics if `prec` is zero.
2086 ///
2087 /// # Examples
2088 /// ```
2089 /// use malachite_base::num::basic::traits::{NaN, One};
2090 /// use malachite_float::Float;
2091 /// use std::cmp::Ordering::*;
2092 ///
2093 /// let mut x = Float::ONE;
2094 /// let mut c = Float::NAN;
2095 /// assert_eq!(
2096 /// x.sin_cos_with_period_prec_assign(&mut c, 7, 10),
2097 /// (Greater, Less)
2098 /// );
2099 /// assert_eq!(x.to_string(), "0.78223");
2100 /// assert_eq!(c.to_string(), "0.62305");
2101 /// ```
2102 #[inline]
2103 pub fn sin_cos_with_period_prec_assign(
2104 &mut self,
2105 cos: &mut Self,
2106 u: u64,
2107 prec: u64,
2108 ) -> (Ordering, Ordering) {
2109 self.sin_cos_with_period_prec_round_assign(cos, u, prec, Nearest)
2110 }
2111
2112 /// Replaces a [`Float`] measured in $u$ths of a turn with its sine and writes its cosine to
2113 /// `cos`, rounding both results to the precision of the input and with the specified rounding
2114 /// mode. The previous value of `cos` is discarded. Two [`Ordering`]s are returned, indicating
2115 /// whether the rounded sine and cosine are less than, equal to, or greater than the exact
2116 /// values. Although `NaN`s are not comparable to any [`Float`], whenever this function sets a
2117 /// `NaN` it also returns `Equal` for it.
2118 ///
2119 /// See [`Float::sin_cos_with_period_round`] and [`Float::sin_cos_with_period_prec_round`]; this
2120 /// function behaves the same way.
2121 ///
2122 /// # Panics
2123 /// Panics if `rm` is `Exact` but the results cannot be represented exactly with the precision
2124 /// of the input (which is the case unless $x/u$ is a multiple of $1/4$, or $x$ is zero or not
2125 /// finite, or $u$ is zero).
2126 ///
2127 /// # Examples
2128 /// ```
2129 /// use malachite_base::num::basic::traits::NaN;
2130 /// use malachite_base::rounding_modes::RoundingMode::*;
2131 /// use malachite_float::Float;
2132 /// use std::cmp::Ordering::*;
2133 ///
2134 /// let mut x = Float::from_unsigned_prec(1u32, 10).0;
2135 /// let mut c = Float::NAN;
2136 /// assert_eq!(
2137 /// x.sin_cos_with_period_round_assign(&mut c, 7, Floor),
2138 /// (Less, Less)
2139 /// );
2140 /// assert_eq!(x.to_string(), "0.78125");
2141 /// assert_eq!(c.to_string(), "0.62305");
2142 /// ```
2143 #[inline]
2144 pub fn sin_cos_with_period_round_assign(
2145 &mut self,
2146 cos: &mut Self,
2147 u: u64,
2148 rm: RoundingMode,
2149 ) -> (Ordering, Ordering) {
2150 let prec = self.significant_bits();
2151 self.sin_cos_with_period_prec_round_assign(cos, u, prec, rm)
2152 }
2153
2154 /// Computes $\sin(2\pi x/u)$ and $\cos(2\pi x/u)$, the sine and cosine of a [`Float`] measured
2155 /// in $u$ths of a turn (so that `u = 360` is degrees), together, rounding both results to the
2156 /// precision of the input and to the nearest [`Float`]s. The [`Float`] is replaced by the sine,
2157 /// and the cosine is written to `cos`, whose previous value is discarded.
2158 ///
2159 /// If either result is equidistant from two [`Float`]s with the precision of the input, the
2160 /// [`Float`] with fewer 1s in its binary expansion is chosen. See [`RoundingMode`] for a
2161 /// description of the `Nearest` rounding mode.
2162 ///
2163 /// See [`Float::sin_cos_with_period_prec_round`] for the error bounds, the special and
2164 /// closed-form cases, overflow and underflow, and the complexity; this function behaves the
2165 /// same way with `prec` equal to the precision of the input and `rm` equal to `Nearest`.
2166 ///
2167 /// If you want to use a rounding mode other than `Nearest`, consider using
2168 /// [`Float::sin_cos_with_period_round_assign`] instead. If you want to specify an output
2169 /// precision, consider using [`Float::sin_cos_with_period_prec_assign`]. If you want both of
2170 /// these things, consider using [`Float::sin_cos_with_period_prec_round_assign`].
2171 ///
2172 /// # Examples
2173 /// ```
2174 /// use malachite_base::num::basic::traits::NaN;
2175 /// use malachite_float::Float;
2176 ///
2177 /// let mut x = Float::from_unsigned_prec(1u32, 10).0;
2178 /// let mut c = Float::NAN;
2179 /// x.sin_cos_with_period_assign(&mut c, 7);
2180 /// assert_eq!(x.to_string(), "0.78223");
2181 /// assert_eq!(c.to_string(), "0.62305");
2182 /// ```
2183 #[inline]
2184 pub fn sin_cos_with_period_assign(&mut self, cos: &mut Self, u: u64) {
2185 let prec = self.significant_bits();
2186 self.sin_cos_with_period_prec_assign(cos, u, prec);
2187 }
2188}
2189
2190impl Float {
2191 /// Computes $\sin(2\pi x/u)$ and $\cos(2\pi x/u)$, the sine and cosine of a [`Rational`]
2192 /// measured in $u$ths of a turn, together, rounding both results to the specified precision and
2193 /// with the specified rounding mode, and returning the results as [`Float`]s. The [`Rational`]
2194 /// is taken by value. Two [`Ordering`]s are also returned, indicating whether the rounded sine
2195 /// and cosine are less than, equal to, or greater than the exact values. Although `NaN`s are
2196 /// not comparable to any [`Float`], whenever this function returns a `NaN` it also returns
2197 /// `Equal` for it.
2198 ///
2199 /// The results are the same as those of [`Float::sin_with_period_rational_prec_round`] and
2200 /// [`Float::cos_with_period_rational_prec_round`], but the reduction of the fraction of a turn,
2201 /// the computation of $2\pi x/u$, and most of the work are shared, so this is faster than the
2202 /// two calls when both values are needed.
2203 ///
2204 /// See [`RoundingMode`] for a description of the possible rounding modes.
2205 ///
2206 /// $$
2207 /// f(x,u,p,m) = (\sin(2\pi x/u)+\varepsilon_s, \cos(2\pi x/u)+\varepsilon_c).
2208 /// $$
2209 /// - If $u=0$, $\varepsilon_s$ and $\varepsilon_c$ may be ignored or assumed to be 0.
2210 /// - If $u\neq 0$ and $m$ is not `Nearest`, then $|\varepsilon_s| < 2^{\lfloor\log_2 |\sin(2\pi
2211 /// x/u)|\rfloor-p+1}$ and $|\varepsilon_c| < 2^{\lfloor\log_2 |\cos(2\pi x/u)|\rfloor-p+1}$.
2212 /// - If $u\neq 0$ and $m$ is `Nearest`, then $|\varepsilon_s| \leq 2^{\lfloor\log_2 |\sin(2\pi
2213 /// x/u)|\rfloor-p}$ and $|\varepsilon_c| \leq 2^{\lfloor\log_2 |\cos(2\pi x/u)|\rfloor-p}$.
2214 ///
2215 /// If the outputs have a precision, it is `prec`.
2216 ///
2217 /// Special cases:
2218 /// - $f(x,0,p,m)=(\text{NaN},\text{NaN})$
2219 /// - $f(0,u,p,m)=(0,1)$
2220 /// - If $x/u$ is a multiple of $1/4$, both results are exact: the sine is $0.0$ with the sign
2221 /// of $x$, $1$, or $-1$, and the cosine is $1$, $0.0$, or $-1$, as for
2222 /// [`Float::sin_with_period_rational_prec_round`] and
2223 /// [`Float::cos_with_period_rational_prec_round`].
2224 ///
2225 /// When $x/u$ in lowest terms has denominator 3, 6, 8, or 12, one result is exactly $\pm1/2$ or
2226 /// both are $\pm\sqrt2/2$, and the other is $\pm\sqrt3/2$; these are computed from a single
2227 /// correctly rounded constant rather than from $\pi$ and a sine and cosine, which is far
2228 /// faster. (A fifth, tenth, or twentieth of a turn has a closed form for only one of the two,
2229 /// and is computed like any other input.)
2230 ///
2231 /// Overflow and underflow:
2232 /// - Since $|\sin(2\pi x/u)|\leq 1$ and $|\cos(2\pi x/u)|\leq 1$, the results never overflow.
2233 /// - Each result underflows exactly as [`Float::sin_with_period_rational_prec_round`] or
2234 /// [`Float::cos_with_period_rational_prec_round`] does: the sine for $x/u$ within
2235 /// $2^{-2^{30}}$ of a multiple of $1/2$ without being one, or for an $x/u$ so small that
2236 /// $2\pi x/u$ is below $2^{-2^{30}}$, and the cosine for $x/u$ within $2^{-2^{30}}$ of an odd
2237 /// multiple of $1/4$ without being one, which takes a denominator of more than $2^{30}$ bits.
2238 /// See those functions for the values returned.
2239 ///
2240 /// If you know you'll be using `Nearest`, consider using
2241 /// [`Float::sin_cos_with_period_rational_prec`] instead.
2242 ///
2243 /// # Worst-case complexity
2244 /// $T(n, m) = O(n (\log n)^3 \log\log n + (n+m) (\log (n+m))^2 \log\log (n+m))$
2245 ///
2246 /// $M(n, m) = O((n+m) \log (n+m))$
2247 ///
2248 /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
2249 /// `x.significant_bits()`: the fraction of a turn is reduced modulo 1 exactly, so only its size
2250 /// and the precision drive the cost, not the magnitude of $x$.
2251 ///
2252 /// # Panics
2253 /// Panics if `prec` is zero, or if `rm` is `Exact` but the results cannot be represented
2254 /// exactly with the given precision (which is the case unless $x/u$ is a multiple of $1/4$, or
2255 /// $x$ or $u$ is zero).
2256 ///
2257 /// # Examples
2258 /// ```
2259 /// use malachite_base::num::basic::traits::One;
2260 /// use malachite_base::rounding_modes::RoundingMode::*;
2261 /// use malachite_float::Float;
2262 /// use malachite_q::Rational;
2263 /// use std::cmp::Ordering::*;
2264 ///
2265 /// let (s, c, o_s, o_c) =
2266 /// Float::sin_cos_with_period_rational_prec_round(Rational::ONE, 7, 10, Floor);
2267 /// assert_eq!(s.to_string(), "0.78125");
2268 /// assert_eq!(c.to_string(), "0.62305");
2269 /// assert_eq!(o_s, Less);
2270 /// assert_eq!(o_c, Less);
2271 ///
2272 /// let (s, c, o_s, o_c) =
2273 /// Float::sin_cos_with_period_rational_prec_round(Rational::ONE, 7, 10, Ceiling);
2274 /// assert_eq!(s.to_string(), "0.78223");
2275 /// assert_eq!(c.to_string(), "0.62402");
2276 /// assert_eq!(o_s, Greater);
2277 /// assert_eq!(o_c, Greater);
2278 ///
2279 /// // a quarter turn is exact
2280 /// let (s, c, o_s, o_c) = Float::sin_cos_with_period_rational_prec_round(
2281 /// Rational::from_unsigneds(1u8, 4),
2282 /// 1,
2283 /// 10,
2284 /// Exact,
2285 /// );
2286 /// assert_eq!(s.to_string(), "1.0000");
2287 /// assert_eq!(c.to_string(), "0.0");
2288 /// assert_eq!(o_s, Equal);
2289 /// assert_eq!(o_c, Equal);
2290 ///
2291 /// // a twelfth of a turn: 1/2 exactly, and sqrt(3)/2
2292 /// let (s, c, o_s, o_c) = Float::sin_cos_with_period_rational_prec_round(
2293 /// Rational::from_unsigneds(1u8, 12),
2294 /// 1,
2295 /// 10,
2296 /// Nearest,
2297 /// );
2298 /// assert_eq!(s.to_string(), "0.50000");
2299 /// assert_eq!(c.to_string(), "0.86621");
2300 /// assert_eq!(o_s, Equal);
2301 /// assert_eq!(o_c, Greater);
2302 /// ```
2303 #[inline]
2304 #[allow(clippy::needless_pass_by_value)]
2305 pub fn sin_cos_with_period_rational_prec_round(
2306 x: Rational,
2307 u: u64,
2308 prec: u64,
2309 rm: RoundingMode,
2310 ) -> (Self, Self, Ordering, Ordering) {
2311 Self::sin_cos_with_period_rational_prec_round_ref(&x, u, prec, rm)
2312 }
2313
2314 /// Computes $\sin(2\pi x/u)$ and $\cos(2\pi x/u)$, the sine and cosine of a [`Rational`]
2315 /// measured in $u$ths of a turn, together, rounding both results to the specified precision and
2316 /// with the specified rounding mode, and returning the results as [`Float`]s. The [`Rational`]
2317 /// is taken by reference. Two [`Ordering`]s are also returned, indicating whether the rounded
2318 /// sine and cosine are less than, equal to, or greater than the exact values. Although `NaN`s
2319 /// are not comparable to any [`Float`], whenever this function returns a `NaN` it also returns
2320 /// `Equal` for it.
2321 ///
2322 /// See [`Float::sin_cos_with_period_rational_prec_round`] for the error bounds, the special
2323 /// cases, overflow and underflow, and the complexity; this function behaves the same way.
2324 ///
2325 /// # Panics
2326 /// Panics if `prec` is zero, or if `rm` is `Exact` but the results cannot be represented
2327 /// exactly with the given precision (which is the case unless $x/u$ is a multiple of $1/4$, or
2328 /// $x$ or $u$ is zero).
2329 ///
2330 /// # Examples
2331 /// ```
2332 /// use malachite_base::num::basic::traits::One;
2333 /// use malachite_base::rounding_modes::RoundingMode::*;
2334 /// use malachite_float::Float;
2335 /// use malachite_q::Rational;
2336 /// use std::cmp::Ordering::*;
2337 ///
2338 /// let (s, c, o_s, o_c) =
2339 /// Float::sin_cos_with_period_rational_prec_round_ref(&Rational::ONE, 7, 10, Floor);
2340 /// assert_eq!(s.to_string(), "0.78125");
2341 /// assert_eq!(c.to_string(), "0.62305");
2342 /// assert_eq!(o_s, Less);
2343 /// assert_eq!(o_c, Less);
2344 ///
2345 /// // an eighth of a turn: sqrt(2)/2 for both
2346 /// let (s, c, o_s, o_c) = Float::sin_cos_with_period_rational_prec_round_ref(
2347 /// &Rational::from_unsigneds(1u8, 8),
2348 /// 1,
2349 /// 10,
2350 /// Nearest,
2351 /// );
2352 /// assert_eq!(s.to_string(), "0.70703");
2353 /// assert_eq!(c.to_string(), "0.70703");
2354 /// assert_eq!(o_s, Less);
2355 /// assert_eq!(o_c, Less);
2356 /// ```
2357 pub fn sin_cos_with_period_rational_prec_round_ref(
2358 x: &Rational,
2359 u: u64,
2360 prec: u64,
2361 rm: RoundingMode,
2362 ) -> (Self, Self, Ordering, Ordering) {
2363 assert_ne!(prec, 0);
2364 // for u = 0, return NaN
2365 if u == 0 {
2366 return (Self::NAN, Self::NAN, Equal, Equal);
2367 }
2368 // sin(0) = 0 (a `Rational` zero has no sign) and cos(0) = 1
2369 if *x == 0u32 {
2370 return (Self::ZERO, Self::one_prec(prec), Equal, Equal);
2371 }
2372 // q = x/u, reduced to (-1, 1) with the sign of x: both functions have period 1 in q, and a
2373 // multiple of u gives a sine of zero with the sign of x (IEEE 754-2019's sinPi) and a
2374 // cosine of 1
2375 let q = x / Rational::from(u) % Rational::ONE;
2376 if q == 0u32 {
2377 return (
2378 if *x < 0u32 {
2379 Self::NEGATIVE_ZERO
2380 } else {
2381 Self::ZERO
2382 },
2383 Self::one_prec(prec),
2384 Equal,
2385 Equal,
2386 );
2387 }
2388 sin_cos_turns_helper(&q, prec, rm)
2389 }
2390
2391 /// Computes $\sin(2\pi x/u)$ and $\cos(2\pi x/u)$, the sine and cosine of a [`Rational`]
2392 /// measured in $u$ths of a turn, together, rounding both results to the nearest value of the
2393 /// specified precision, and returning the results as [`Float`]s. The [`Rational`] is taken by
2394 /// value. Two [`Ordering`]s are also returned, indicating whether the rounded sine and cosine
2395 /// are less than, equal to, or greater than the exact values. Although `NaN`s are not
2396 /// comparable to any [`Float`], whenever this function returns a `NaN` it also returns `Equal`
2397 /// for it.
2398 ///
2399 /// If a result is equidistant from two [`Float`]s with the specified precision, the [`Float`]
2400 /// with fewer 1s in its binary expansion is chosen. See [`RoundingMode`] for a description of
2401 /// the `Nearest` rounding mode.
2402 ///
2403 /// See [`Float::sin_cos_with_period_rational_prec_round`] for the error bounds, the special
2404 /// cases, overflow and underflow, and the complexity; this function behaves the same way with
2405 /// `Nearest`.
2406 ///
2407 /// If you want to use a rounding mode other than `Nearest`, consider using
2408 /// [`Float::sin_cos_with_period_rational_prec_round`] instead.
2409 ///
2410 /// # Panics
2411 /// Panics if `prec` is zero.
2412 ///
2413 /// # Examples
2414 /// ```
2415 /// use malachite_base::num::basic::traits::One;
2416 /// use malachite_float::Float;
2417 /// use malachite_q::Rational;
2418 /// use std::cmp::Ordering::*;
2419 ///
2420 /// let (s, c, o_s, o_c) = Float::sin_cos_with_period_rational_prec(Rational::ONE, 7, 10);
2421 /// assert_eq!(s.to_string(), "0.78223");
2422 /// assert_eq!(c.to_string(), "0.62305");
2423 /// assert_eq!(o_s, Greater);
2424 /// assert_eq!(o_c, Less);
2425 ///
2426 /// let (s, c, o_s, o_c) = Float::sin_cos_with_period_rational_prec(Rational::ONE, 360, 53);
2427 /// assert_eq!(s.to_string(), "0.017452406437283512");
2428 /// assert_eq!(c.to_string(), "0.99984769515639127");
2429 /// assert_eq!(o_s, Less);
2430 /// assert_eq!(o_c, Greater);
2431 /// ```
2432 #[inline]
2433 #[allow(clippy::needless_pass_by_value)]
2434 pub fn sin_cos_with_period_rational_prec(
2435 x: Rational,
2436 u: u64,
2437 prec: u64,
2438 ) -> (Self, Self, Ordering, Ordering) {
2439 Self::sin_cos_with_period_rational_prec_round_ref(&x, u, prec, Nearest)
2440 }
2441
2442 /// Computes $\sin(2\pi x/u)$ and $\cos(2\pi x/u)$, the sine and cosine of a [`Rational`]
2443 /// measured in $u$ths of a turn, together, rounding both results to the nearest value of the
2444 /// specified precision, and returning the results as [`Float`]s. The [`Rational`] is taken by
2445 /// reference. Two [`Ordering`]s are also returned, indicating whether the rounded sine and
2446 /// cosine are less than, equal to, or greater than the exact values. Although `NaN`s are not
2447 /// comparable to any [`Float`], whenever this function returns a `NaN` it also returns `Equal`
2448 /// for it.
2449 ///
2450 /// See [`Float::sin_cos_with_period_rational_prec`] and
2451 /// [`Float::sin_cos_with_period_rational_prec_round`]; this function behaves the same way.
2452 ///
2453 /// # Panics
2454 /// Panics if `prec` is zero.
2455 ///
2456 /// # Examples
2457 /// ```
2458 /// use malachite_base::num::basic::traits::One;
2459 /// use malachite_float::Float;
2460 /// use malachite_q::Rational;
2461 /// use std::cmp::Ordering::*;
2462 ///
2463 /// let (s, c, o_s, o_c) = Float::sin_cos_with_period_rational_prec_ref(&Rational::ONE, 7, 10);
2464 /// assert_eq!(s.to_string(), "0.78223");
2465 /// assert_eq!(c.to_string(), "0.62305");
2466 /// assert_eq!(o_s, Greater);
2467 /// assert_eq!(o_c, Less);
2468 /// ```
2469 #[inline]
2470 pub fn sin_cos_with_period_rational_prec_ref(
2471 x: &Rational,
2472 u: u64,
2473 prec: u64,
2474 ) -> (Self, Self, Ordering, Ordering) {
2475 Self::sin_cos_with_period_rational_prec_round_ref(x, u, prec, Nearest)
2476 }
2477}
2478
2479impl Float {
2480 /// Computes $\sin(\pi x)$ and $\cos(\pi x)$, the sine and cosine of a [`Float`] measured in
2481 /// half-turns, together, rounding both results to the specified precision and with the
2482 /// specified rounding mode. The [`Float`] is taken by value. Two [`Ordering`]s are also
2483 /// returned, indicating whether the rounded sine and cosine are less than, equal to, or greater
2484 /// than the exact values. Although `NaN`s are not comparable to any [`Float`], whenever this
2485 /// function returns a `NaN` it also returns `Equal` for it.
2486 ///
2487 /// This is `sin_cos_with_period` with a period of 2: see
2488 /// [`Float::sin_cos_with_period_prec_round`] for the error bounds, the special and closed-form
2489 /// cases (multiples of $1/2$ give exact pairs from $\pm0.0$ and $\pm1$, and odd multiples of
2490 /// $1/6$, $1/4$, and $1/3$ have closed forms for both), overflow and underflow, and the
2491 /// complexity, with $u = 2$.
2492 ///
2493 /// # Panics
2494 /// Panics if `prec` is zero, or if `rm` is `Exact` but the results cannot be represented
2495 /// exactly with the given precision.
2496 ///
2497 /// # Examples
2498 /// ```
2499 /// use malachite_base::num::basic::traits::One;
2500 /// use malachite_base::rounding_modes::RoundingMode::*;
2501 /// use malachite_float::Float;
2502 /// use std::cmp::Ordering::*;
2503 ///
2504 /// let (s, c, o_s, o_c) = Float::from(0.1f64).sin_cos_pi_prec_round(10, Floor);
2505 /// assert_eq!(s.to_string(), "0.30859");
2506 /// assert_eq!(c.to_string(), "0.95020");
2507 /// assert_eq!(o_s, Less);
2508 /// assert_eq!(o_c, Less);
2509 ///
2510 /// let (s, c, o_s, o_c) = Float::from(0.1f64).sin_cos_pi_prec_round(10, Ceiling);
2511 /// assert_eq!(s.to_string(), "0.30908");
2512 /// assert_eq!(c.to_string(), "0.95117");
2513 /// assert_eq!(o_s, Greater);
2514 /// assert_eq!(o_c, Greater);
2515 ///
2516 /// // a half-turn is exact
2517 /// let (s, c, o_s, o_c) = Float::ONE.sin_cos_pi_prec_round(10, Exact);
2518 /// assert_eq!(s.to_string(), "0.0");
2519 /// assert_eq!(c.to_string(), "-1.0000");
2520 /// assert_eq!(o_s, Equal);
2521 /// assert_eq!(o_c, Equal);
2522 /// ```
2523 #[inline]
2524 pub fn sin_cos_pi_prec_round(
2525 self,
2526 prec: u64,
2527 rm: RoundingMode,
2528 ) -> (Self, Self, Ordering, Ordering) {
2529 self.sin_cos_with_period_prec_round(2, prec, rm)
2530 }
2531
2532 /// Computes $\sin(\pi x)$ and $\cos(\pi x)$, the sine and cosine of a [`Float`] measured in
2533 /// half-turns, together, rounding both results to the specified precision and with the
2534 /// specified rounding mode. The [`Float`] is taken by reference. Two [`Ordering`]s are also
2535 /// returned, indicating whether the rounded sine and cosine are less than, equal to, or greater
2536 /// than the exact values. Although `NaN`s are not comparable to any [`Float`], whenever this
2537 /// function returns a `NaN` it also returns `Equal` for it.
2538 ///
2539 /// This is `sin_cos_with_period` with a period of 2: see
2540 /// [`Float::sin_cos_with_period_prec_round_ref`] for the error bounds, the special and
2541 /// closed-form cases, overflow and underflow, and the complexity, with $u = 2$.
2542 ///
2543 /// # Panics
2544 /// Panics if `prec` is zero, or if `rm` is `Exact` but the results cannot be represented
2545 /// exactly with the given precision.
2546 ///
2547 /// # Examples
2548 /// ```
2549 /// use malachite_base::rounding_modes::RoundingMode::*;
2550 /// use malachite_float::Float;
2551 /// use std::cmp::Ordering::*;
2552 ///
2553 /// let (s, c, o_s, o_c) = Float::from(0.1f64).sin_cos_pi_prec_round_ref(10, Floor);
2554 /// assert_eq!(s.to_string(), "0.30859");
2555 /// assert_eq!(c.to_string(), "0.95020");
2556 /// assert_eq!(o_s, Less);
2557 /// assert_eq!(o_c, Less);
2558 /// ```
2559 #[inline]
2560 pub fn sin_cos_pi_prec_round_ref(
2561 &self,
2562 prec: u64,
2563 rm: RoundingMode,
2564 ) -> (Self, Self, Ordering, Ordering) {
2565 self.sin_cos_with_period_prec_round_ref(2, prec, rm)
2566 }
2567
2568 /// Computes $\sin(\pi x)$ and $\cos(\pi x)$, the sine and cosine of a [`Float`] measured in
2569 /// half-turns, together, rounding both results to the nearest value of the specified precision.
2570 /// The [`Float`] is taken by value. Two [`Ordering`]s are also returned, indicating whether the
2571 /// rounded sine and cosine are less than, equal to, or greater than the exact values. Although
2572 /// `NaN`s are not comparable to any [`Float`], whenever this function returns a `NaN` it also
2573 /// returns `Equal` for it.
2574 ///
2575 /// This is `sin_cos_with_period` with a period of 2: see [`Float::sin_cos_with_period_prec`]
2576 /// for the error bounds, the special and closed-form cases, overflow and underflow, and the
2577 /// complexity, with $u = 2$.
2578 ///
2579 /// # Panics
2580 /// Panics if `prec` is zero.
2581 ///
2582 /// # Examples
2583 /// ```
2584 /// use malachite_float::Float;
2585 /// use std::cmp::Ordering::*;
2586 ///
2587 /// let (s, c, o_s, o_c) = Float::from(0.1f64).sin_cos_pi_prec(10);
2588 /// assert_eq!(s.to_string(), "0.30908");
2589 /// assert_eq!(c.to_string(), "0.95117");
2590 /// assert_eq!(o_s, Greater);
2591 /// assert_eq!(o_c, Greater);
2592 /// ```
2593 #[inline]
2594 pub fn sin_cos_pi_prec(self, prec: u64) -> (Self, Self, Ordering, Ordering) {
2595 self.sin_cos_with_period_prec(2, prec)
2596 }
2597
2598 /// Computes $\sin(\pi x)$ and $\cos(\pi x)$, the sine and cosine of a [`Float`] measured in
2599 /// half-turns, together, rounding both results to the nearest value of the specified precision.
2600 /// The [`Float`] is taken by reference. Two [`Ordering`]s are also returned, indicating whether
2601 /// the rounded sine and cosine are less than, equal to, or greater than the exact values.
2602 /// Although `NaN`s are not comparable to any [`Float`], whenever this function returns a `NaN`
2603 /// it also returns `Equal` for it.
2604 ///
2605 /// This is `sin_cos_with_period` with a period of 2: see
2606 /// [`Float::sin_cos_with_period_prec_ref`] for the error bounds, the special and closed-form
2607 /// cases, overflow and underflow, and the complexity, with $u = 2$.
2608 ///
2609 /// # Panics
2610 /// Panics if `prec` is zero.
2611 ///
2612 /// # Examples
2613 /// ```
2614 /// use malachite_float::Float;
2615 /// use std::cmp::Ordering::*;
2616 ///
2617 /// let (s, c, o_s, o_c) = Float::from(0.1f64).sin_cos_pi_prec_ref(10);
2618 /// assert_eq!(s.to_string(), "0.30908");
2619 /// assert_eq!(c.to_string(), "0.95117");
2620 /// assert_eq!(o_s, Greater);
2621 /// assert_eq!(o_c, Greater);
2622 /// ```
2623 #[inline]
2624 pub fn sin_cos_pi_prec_ref(&self, prec: u64) -> (Self, Self, Ordering, Ordering) {
2625 self.sin_cos_with_period_prec_ref(2, prec)
2626 }
2627
2628 /// Computes $\sin(\pi x)$ and $\cos(\pi x)$, the sine and cosine of a [`Float`] measured in
2629 /// half-turns, together, rounding both results to the precision of the input and with the
2630 /// specified rounding mode. The [`Float`] is taken by value. Two [`Ordering`]s are also
2631 /// returned, indicating whether the rounded sine and cosine are less than, equal to, or greater
2632 /// than the exact values. Although `NaN`s are not comparable to any [`Float`], whenever this
2633 /// function returns a `NaN` it also returns `Equal` for it.
2634 ///
2635 /// This is `sin_cos_with_period` with a period of 2: see [`Float::sin_cos_with_period_round`]
2636 /// for the error bounds, the special and closed-form cases, overflow and underflow, and the
2637 /// complexity, with $u = 2$.
2638 ///
2639 /// # Panics
2640 /// Panics if `rm` is `Exact` but the results cannot be represented exactly with the precision
2641 /// of the input.
2642 ///
2643 /// # Examples
2644 /// ```
2645 /// use malachite_base::rounding_modes::RoundingMode::*;
2646 /// use malachite_float::Float;
2647 /// use std::cmp::Ordering::*;
2648 ///
2649 /// let (s, c, o_s, o_c) = Float::from(0.1f64).sin_cos_pi_round(Floor);
2650 /// assert_eq!(s.to_string(), "0.30901699437494734");
2651 /// assert_eq!(c.to_string(), "0.95105651629515342");
2652 /// assert_eq!(o_s, Less);
2653 /// assert_eq!(o_c, Less);
2654 /// ```
2655 #[inline]
2656 pub fn sin_cos_pi_round(self, rm: RoundingMode) -> (Self, Self, Ordering, Ordering) {
2657 self.sin_cos_with_period_round(2, rm)
2658 }
2659
2660 /// Computes $\sin(\pi x)$ and $\cos(\pi x)$, the sine and cosine of a [`Float`] measured in
2661 /// half-turns, together, rounding both results to the precision of the input and with the
2662 /// specified rounding mode. The [`Float`] is taken by reference. Two [`Ordering`]s are also
2663 /// returned, indicating whether the rounded sine and cosine are less than, equal to, or greater
2664 /// than the exact values. Although `NaN`s are not comparable to any [`Float`], whenever this
2665 /// function returns a `NaN` it also returns `Equal` for it.
2666 ///
2667 /// This is `sin_cos_with_period` with a period of 2: see
2668 /// [`Float::sin_cos_with_period_round_ref`] for the error bounds, the special and closed-form
2669 /// cases, overflow and underflow, and the complexity, with $u = 2$.
2670 ///
2671 /// # Panics
2672 /// Panics if `rm` is `Exact` but the results cannot be represented exactly with the precision
2673 /// of the input.
2674 ///
2675 /// # Examples
2676 /// ```
2677 /// use malachite_base::rounding_modes::RoundingMode::*;
2678 /// use malachite_float::Float;
2679 /// use std::cmp::Ordering::*;
2680 ///
2681 /// let (s, c, o_s, o_c) = Float::from(0.1f64).sin_cos_pi_round_ref(Floor);
2682 /// assert_eq!(s.to_string(), "0.30901699437494734");
2683 /// assert_eq!(c.to_string(), "0.95105651629515342");
2684 /// assert_eq!(o_s, Less);
2685 /// assert_eq!(o_c, Less);
2686 /// ```
2687 #[inline]
2688 pub fn sin_cos_pi_round_ref(&self, rm: RoundingMode) -> (Self, Self, Ordering, Ordering) {
2689 self.sin_cos_with_period_round_ref(2, rm)
2690 }
2691
2692 /// Computes $\sin(\pi x)$ and $\cos(\pi x)$, the sine and cosine of a [`Float`] measured in
2693 /// half-turns, together, rounding both results to the precision of the input and to the nearest
2694 /// [`Float`]s. The [`Float`] is taken by value.
2695 ///
2696 /// If either result is equidistant from two [`Float`]s with the precision of the input, the
2697 /// [`Float`] with fewer 1s in its binary expansion is chosen. See [`RoundingMode`] for a
2698 /// description of the `Nearest` rounding mode.
2699 ///
2700 /// This is `sin_cos_with_period` with a period of 2: see [`Float::sin_cos_with_period`] for the
2701 /// error bounds, the special and closed-form cases, overflow and underflow, and the complexity,
2702 /// with $u = 2$.
2703 ///
2704 /// If you want to use a rounding mode other than `Nearest`, consider using
2705 /// [`Float::sin_cos_pi_round`] instead. If you want to specify an output precision, consider
2706 /// using [`Float::sin_cos_pi_prec`]. If you want both of these things, consider using
2707 /// [`Float::sin_cos_pi_prec_round`].
2708 ///
2709 /// # Examples
2710 /// ```
2711 /// use malachite_float::Float;
2712 ///
2713 /// let (s, c) = Float::from(0.1f64).sin_cos_pi();
2714 /// assert_eq!(s.to_string(), "0.30901699437494745");
2715 /// assert_eq!(c.to_string(), "0.95105651629515364");
2716 /// ```
2717 #[inline]
2718 pub fn sin_cos_pi(self) -> (Self, Self) {
2719 let prec = self.significant_bits();
2720 let (s, c, _, _) = self.sin_cos_pi_prec(prec);
2721 (s, c)
2722 }
2723
2724 /// Computes $\sin(\pi x)$ and $\cos(\pi x)$, the sine and cosine of a [`Float`] measured in
2725 /// half-turns, together, rounding both results to the precision of the input and to the nearest
2726 /// [`Float`]s. The [`Float`] is taken by reference.
2727 ///
2728 /// If either result is equidistant from two [`Float`]s with the precision of the input, the
2729 /// [`Float`] with fewer 1s in its binary expansion is chosen. See [`RoundingMode`] for a
2730 /// description of the `Nearest` rounding mode.
2731 ///
2732 /// This is `sin_cos_with_period` with a period of 2: see [`Float::sin_cos_with_period`] for the
2733 /// error bounds, the special and closed-form cases, overflow and underflow, and the complexity,
2734 /// with $u = 2$.
2735 ///
2736 /// If you want to use a rounding mode other than `Nearest`, consider using
2737 /// [`Float::sin_cos_pi_round_ref`] instead. If you want to specify an output precision,
2738 /// consider using [`Float::sin_cos_pi_prec_ref`]. If you want both of these things, consider
2739 /// using [`Float::sin_cos_pi_prec_round_ref`].
2740 ///
2741 /// # Examples
2742 /// ```
2743 /// use malachite_float::Float;
2744 ///
2745 /// let (s, c) = (&Float::from(0.1f64)).sin_cos_pi_ref();
2746 /// assert_eq!(s.to_string(), "0.30901699437494745");
2747 /// assert_eq!(c.to_string(), "0.95105651629515364");
2748 /// ```
2749 #[inline]
2750 pub fn sin_cos_pi_ref(&self) -> (Self, Self) {
2751 let (s, c, _, _) = self.sin_cos_pi_prec_ref(self.significant_bits());
2752 (s, c)
2753 }
2754
2755 /// Replaces a [`Float`] measured in half-turns with its sine and writes its cosine to `cos`,
2756 /// rounding both results to the specified precision and with the specified rounding mode. The
2757 /// previous value of `cos` is discarded. Two [`Ordering`]s are returned, indicating whether the
2758 /// rounded sine and cosine are less than, equal to, or greater than the exact values. Although
2759 /// `NaN`s are not comparable to any [`Float`], whenever this function sets a `NaN` it also
2760 /// returns `Equal` for it.
2761 ///
2762 /// This is `sin_cos_with_period` with a period of 2: see
2763 /// [`Float::sin_cos_with_period_prec_round_assign`] for the error bounds, the special and
2764 /// closed-form cases, overflow and underflow, and the complexity, with $u = 2$.
2765 ///
2766 /// # Panics
2767 /// Panics if `prec` is zero, or if `rm` is `Exact` but the results cannot be represented
2768 /// exactly with the given precision.
2769 ///
2770 /// # Examples
2771 /// ```
2772 /// use malachite_base::num::basic::traits::NaN;
2773 /// use malachite_base::rounding_modes::RoundingMode::*;
2774 /// use malachite_float::Float;
2775 /// use std::cmp::Ordering::*;
2776 ///
2777 /// let mut x = Float::from(0.1f64);
2778 /// let mut c = Float::NAN;
2779 /// assert_eq!(
2780 /// x.sin_cos_pi_prec_round_assign(&mut c, 10, Floor),
2781 /// (Less, Less)
2782 /// );
2783 /// assert_eq!(x.to_string(), "0.30859");
2784 /// assert_eq!(c.to_string(), "0.95020");
2785 /// ```
2786 #[inline]
2787 pub fn sin_cos_pi_prec_round_assign(
2788 &mut self,
2789 cos: &mut Self,
2790 prec: u64,
2791 rm: RoundingMode,
2792 ) -> (Ordering, Ordering) {
2793 self.sin_cos_with_period_prec_round_assign(cos, 2, prec, rm)
2794 }
2795
2796 /// Replaces a [`Float`] measured in half-turns with its sine and writes its cosine to `cos`,
2797 /// rounding both results to the nearest value of the specified precision. The previous value of
2798 /// `cos` is discarded. Two [`Ordering`]s are returned, indicating whether the rounded sine and
2799 /// cosine are less than, equal to, or greater than the exact values. Although `NaN`s are not
2800 /// comparable to any [`Float`], whenever this function sets a `NaN` it also returns `Equal` for
2801 /// it.
2802 ///
2803 /// This is `sin_cos_with_period` with a period of 2: see
2804 /// [`Float::sin_cos_with_period_prec_assign`] for the error bounds, the special and closed-form
2805 /// cases, overflow and underflow, and the complexity, with $u = 2$.
2806 ///
2807 /// # Panics
2808 /// Panics if `prec` is zero.
2809 ///
2810 /// # Examples
2811 /// ```
2812 /// use malachite_base::num::basic::traits::NaN;
2813 /// use malachite_float::Float;
2814 /// use std::cmp::Ordering::*;
2815 ///
2816 /// let mut x = Float::from(0.1f64);
2817 /// let mut c = Float::NAN;
2818 /// assert_eq!(x.sin_cos_pi_prec_assign(&mut c, 10), (Greater, Greater));
2819 /// assert_eq!(x.to_string(), "0.30908");
2820 /// assert_eq!(c.to_string(), "0.95117");
2821 /// ```
2822 #[inline]
2823 pub fn sin_cos_pi_prec_assign(&mut self, cos: &mut Self, prec: u64) -> (Ordering, Ordering) {
2824 self.sin_cos_with_period_prec_assign(cos, 2, prec)
2825 }
2826
2827 /// Replaces a [`Float`] measured in half-turns with its sine and writes its cosine to `cos`,
2828 /// rounding both results to the precision of the input and with the specified rounding mode.
2829 /// The previous value of `cos` is discarded. Two [`Ordering`]s are returned, indicating whether
2830 /// the rounded sine and cosine are less than, equal to, or greater than the exact values.
2831 /// Although `NaN`s are not comparable to any [`Float`], whenever this function sets a `NaN` it
2832 /// also returns `Equal` for it.
2833 ///
2834 /// This is `sin_cos_with_period` with a period of 2: see
2835 /// [`Float::sin_cos_with_period_round_assign`] for the error bounds, the special and
2836 /// closed-form cases, overflow and underflow, and the complexity, with $u = 2$.
2837 ///
2838 /// # Panics
2839 /// Panics if `rm` is `Exact` but the results cannot be represented exactly with the precision
2840 /// of the input.
2841 ///
2842 /// # Examples
2843 /// ```
2844 /// use malachite_base::num::basic::traits::NaN;
2845 /// use malachite_base::rounding_modes::RoundingMode::*;
2846 /// use malachite_float::Float;
2847 /// use std::cmp::Ordering::*;
2848 ///
2849 /// let mut x = Float::from(0.1f64);
2850 /// let mut c = Float::NAN;
2851 /// assert_eq!(x.sin_cos_pi_round_assign(&mut c, Floor), (Less, Less));
2852 /// assert_eq!(x.to_string(), "0.30901699437494734");
2853 /// assert_eq!(c.to_string(), "0.95105651629515342");
2854 /// ```
2855 #[inline]
2856 pub fn sin_cos_pi_round_assign(
2857 &mut self,
2858 cos: &mut Self,
2859 rm: RoundingMode,
2860 ) -> (Ordering, Ordering) {
2861 self.sin_cos_with_period_round_assign(cos, 2, rm)
2862 }
2863
2864 /// Computes $\sin(\pi x)$ and $\cos(\pi x)$, the sine and cosine of a [`Float`] measured in
2865 /// half-turns, together, rounding both results to the precision of the input and to the nearest
2866 /// [`Float`]s. The [`Float`] is replaced by the sine, and the cosine is written to `cos`, whose
2867 /// previous value is discarded.
2868 ///
2869 /// If either result is equidistant from two [`Float`]s with the precision of the input, the
2870 /// [`Float`] with fewer 1s in its binary expansion is chosen. See [`RoundingMode`] for a
2871 /// description of the `Nearest` rounding mode.
2872 ///
2873 /// This is `sin_cos_with_period` with a period of 2: see [`Float::sin_cos_with_period`] for the
2874 /// error bounds, the special and closed-form cases, overflow and underflow, and the complexity,
2875 /// with $u = 2$.
2876 ///
2877 /// If you want to use a rounding mode other than `Nearest`, consider using
2878 /// [`Float::sin_cos_pi_round_assign`] instead. If you want to specify an output precision,
2879 /// consider using [`Float::sin_cos_pi_prec_assign`]. If you want both of these things, consider
2880 /// using [`Float::sin_cos_pi_prec_round_assign`].
2881 ///
2882 /// # Examples
2883 /// ```
2884 /// use malachite_base::num::basic::traits::NaN;
2885 /// use malachite_float::Float;
2886 ///
2887 /// let mut x = Float::from(0.1f64);
2888 /// let mut c = Float::NAN;
2889 /// x.sin_cos_pi_assign(&mut c);
2890 /// assert_eq!(x.to_string(), "0.30901699437494745");
2891 /// assert_eq!(c.to_string(), "0.95105651629515364");
2892 /// ```
2893 #[inline]
2894 pub fn sin_cos_pi_assign(&mut self, cos: &mut Self) {
2895 let prec = self.significant_bits();
2896 self.sin_cos_pi_prec_assign(cos, prec);
2897 }
2898}
2899
2900impl Float {
2901 /// Computes $\sin(\pi x)$ and $\cos(\pi x)$, the sine and cosine of a [`Rational`] measured in
2902 /// half-turns, together, rounding both results to the specified precision and with the
2903 /// specified rounding mode, and returning the results as [`Float`]s. The [`Rational`] is taken
2904 /// by value. Two [`Ordering`]s are also returned, indicating whether the rounded sine and
2905 /// cosine are less than, equal to, or greater than the exact values.
2906 ///
2907 /// This is `sin_cos_with_period_rational` with a period of 2: see
2908 /// [`Float::sin_cos_with_period_rational_prec_round`] for the error bounds, the special and
2909 /// closed-form cases (multiples of $1/2$ give exact pairs from $\pm0.0$ and $\pm1$, and odd
2910 /// multiples of $1/6$, $1/4$, and $1/3$ have closed forms for both), overflow and underflow,
2911 /// and the complexity, with $u = 2$.
2912 ///
2913 /// # Panics
2914 /// Panics if `prec` is zero, or if `rm` is `Exact` but the results cannot be represented
2915 /// exactly with the given precision.
2916 ///
2917 /// # Examples
2918 /// ```
2919 /// use malachite_base::rounding_modes::RoundingMode::*;
2920 /// use malachite_float::Float;
2921 /// use malachite_q::Rational;
2922 /// use std::cmp::Ordering::*;
2923 ///
2924 /// let (s, c, o_s, o_c) =
2925 /// Float::sin_cos_pi_rational_prec_round(Rational::from_unsigneds(1u8, 7), 10, Floor);
2926 /// assert_eq!(s.to_string(), "0.43359");
2927 /// assert_eq!(c.to_string(), "0.90039");
2928 /// assert_eq!(o_s, Less);
2929 /// assert_eq!(o_c, Less);
2930 ///
2931 /// // a sixth of a half-turn: 1/2 exactly, and sqrt(3)/2
2932 /// let (s, c, o_s, o_c) =
2933 /// Float::sin_cos_pi_rational_prec_round(Rational::from_unsigneds(1u8, 6), 10, Nearest);
2934 /// assert_eq!(s.to_string(), "0.50000");
2935 /// assert_eq!(c.to_string(), "0.86621");
2936 /// assert_eq!(o_s, Equal);
2937 /// assert_eq!(o_c, Greater);
2938 /// ```
2939 #[inline]
2940 #[allow(clippy::needless_pass_by_value)]
2941 pub fn sin_cos_pi_rational_prec_round(
2942 x: Rational,
2943 prec: u64,
2944 rm: RoundingMode,
2945 ) -> (Self, Self, Ordering, Ordering) {
2946 Self::sin_cos_with_period_rational_prec_round_ref(&x, 2, prec, rm)
2947 }
2948
2949 /// Computes $\sin(\pi x)$ and $\cos(\pi x)$, the sine and cosine of a [`Rational`] measured in
2950 /// half-turns, together, rounding both results to the specified precision and with the
2951 /// specified rounding mode, and returning the results as [`Float`]s. The [`Rational`] is taken
2952 /// by reference. Two [`Ordering`]s are also returned, indicating whether the rounded sine and
2953 /// cosine are less than, equal to, or greater than the exact values.
2954 ///
2955 /// This is `sin_cos_with_period_rational` with a period of 2: see
2956 /// [`Float::sin_cos_with_period_rational_prec_round_ref`] for the error bounds, the special and
2957 /// closed-form cases, overflow and underflow, and the complexity, with $u = 2$.
2958 ///
2959 /// # Panics
2960 /// Panics if `prec` is zero, or if `rm` is `Exact` but the results cannot be represented
2961 /// exactly with the given precision.
2962 ///
2963 /// # Examples
2964 /// ```
2965 /// use malachite_base::rounding_modes::RoundingMode::*;
2966 /// use malachite_float::Float;
2967 /// use malachite_q::Rational;
2968 /// use std::cmp::Ordering::*;
2969 ///
2970 /// let (s, c, o_s, o_c) =
2971 /// Float::sin_cos_pi_rational_prec_round_ref(&Rational::from_unsigneds(1u8, 7), 10, Floor);
2972 /// assert_eq!(s.to_string(), "0.43359");
2973 /// assert_eq!(c.to_string(), "0.90039");
2974 /// assert_eq!(o_s, Less);
2975 /// assert_eq!(o_c, Less);
2976 /// ```
2977 #[inline]
2978 pub fn sin_cos_pi_rational_prec_round_ref(
2979 x: &Rational,
2980 prec: u64,
2981 rm: RoundingMode,
2982 ) -> (Self, Self, Ordering, Ordering) {
2983 Self::sin_cos_with_period_rational_prec_round_ref(x, 2, prec, rm)
2984 }
2985
2986 /// Computes $\sin(\pi x)$ and $\cos(\pi x)$, the sine and cosine of a [`Rational`] measured in
2987 /// half-turns, together, rounding both results to the nearest value of the specified precision,
2988 /// and returning the results as [`Float`]s. The [`Rational`] is taken by value. Two
2989 /// [`Ordering`]s are also returned, indicating whether the rounded sine and cosine are less
2990 /// than, equal to, or greater than the exact values.
2991 ///
2992 /// This is `sin_cos_with_period_rational` with a period of 2: see
2993 /// [`Float::sin_cos_with_period_rational_prec`] for the error bounds, the special and
2994 /// closed-form cases, overflow and underflow, and the complexity, with $u = 2$.
2995 ///
2996 /// # Panics
2997 /// Panics if `prec` is zero.
2998 ///
2999 /// # Examples
3000 /// ```
3001 /// use malachite_float::Float;
3002 /// use malachite_q::Rational;
3003 /// use std::cmp::Ordering::*;
3004 ///
3005 /// let (s, c, o_s, o_c) =
3006 /// Float::sin_cos_pi_rational_prec(Rational::from_unsigneds(1u8, 7), 10);
3007 /// assert_eq!(s.to_string(), "0.43408");
3008 /// assert_eq!(c.to_string(), "0.90137");
3009 /// assert_eq!(o_s, Greater);
3010 /// assert_eq!(o_c, Greater);
3011 /// ```
3012 #[inline]
3013 #[allow(clippy::needless_pass_by_value)]
3014 pub fn sin_cos_pi_rational_prec(x: Rational, prec: u64) -> (Self, Self, Ordering, Ordering) {
3015 Self::sin_cos_with_period_rational_prec_ref(&x, 2, prec)
3016 }
3017
3018 /// Computes $\sin(\pi x)$ and $\cos(\pi x)$, the sine and cosine of a [`Rational`] measured in
3019 /// half-turns, together, rounding both results to the nearest value of the specified precision,
3020 /// and returning the results as [`Float`]s. The [`Rational`] is taken by reference. Two
3021 /// [`Ordering`]s are also returned, indicating whether the rounded sine and cosine are less
3022 /// than, equal to, or greater than the exact values.
3023 ///
3024 /// This is `sin_cos_with_period_rational` with a period of 2: see
3025 /// [`Float::sin_cos_with_period_rational_prec_ref`] for the error bounds, the special and
3026 /// closed-form cases, overflow and underflow, and the complexity, with $u = 2$.
3027 ///
3028 /// # Panics
3029 /// Panics if `prec` is zero.
3030 ///
3031 /// # Examples
3032 /// ```
3033 /// use malachite_float::Float;
3034 /// use malachite_q::Rational;
3035 /// use std::cmp::Ordering::*;
3036 ///
3037 /// let (s, c, o_s, o_c) =
3038 /// Float::sin_cos_pi_rational_prec_ref(&Rational::from_unsigneds(1u8, 7), 10);
3039 /// assert_eq!(s.to_string(), "0.43408");
3040 /// assert_eq!(c.to_string(), "0.90137");
3041 /// assert_eq!(o_s, Greater);
3042 /// assert_eq!(o_c, Greater);
3043 /// ```
3044 #[inline]
3045 pub fn sin_cos_pi_rational_prec_ref(
3046 x: &Rational,
3047 prec: u64,
3048 ) -> (Self, Self, Ordering, Ordering) {
3049 Self::sin_cos_with_period_rational_prec_ref(x, 2, prec)
3050 }
3051}
3052
3053impl SinCos for Float {
3054 type Output = Self;
3055
3056 /// Computes $\sin x$ and $\cos x$, the sine and cosine of a [`Float`], together, taking it by
3057 /// value.
3058 ///
3059 /// If the outputs have a precision, it is the precision of the input. If a result is
3060 /// equidistant from two [`Float`]s with the specified precision, the [`Float`] with fewer 1s in
3061 /// its binary expansion is chosen. See [`RoundingMode`] for a description of the `Nearest`
3062 /// rounding mode.
3063 ///
3064 /// $$
3065 /// f(x) = (\sin x+\varepsilon_s, \cos x+\varepsilon_c).
3066 /// $$
3067 /// - If $x$ is not finite, $\varepsilon_s$ and $\varepsilon_c$ may be ignored or assumed to be
3068 /// 0.
3069 /// - If $x$ is finite, then $|\varepsilon_s| < 2^{\lfloor\log_2 |\sin x|\rfloor-p}$ and
3070 /// $|\varepsilon_c| < 2^{\lfloor\log_2 |\cos x|\rfloor-p}$, where $p$ is the precision of the
3071 /// input.
3072 ///
3073 /// Special cases:
3074 /// - $f(\text{NaN})=(\text{NaN},\text{NaN})$
3075 /// - $f(\pm\infty)=(\text{NaN},\text{NaN})$
3076 /// - $f(\pm0.0)=(\pm0.0,1.0)$
3077 ///
3078 /// See [`Float::sin_cos_prec_round`] for overflow, underflow, and the complexity.
3079 ///
3080 /// If you want to use a rounding mode other than `Nearest`, consider using
3081 /// [`Float::sin_cos_round`] instead. If you want to specify an output precision, consider using
3082 /// [`Float::sin_cos_prec`] instead. If you want both of these things, consider using
3083 /// [`Float::sin_cos_prec_round`] instead.
3084 ///
3085 /// # Examples
3086 /// ```
3087 /// use malachite_base::num::arithmetic::traits::SinCos;
3088 /// use malachite_base::num::basic::traits::{NaN, NegativeZero, Zero};
3089 /// use malachite_float::Float;
3090 ///
3091 /// let (s, c) = Float::NAN.sin_cos();
3092 /// assert!(s.is_nan());
3093 /// assert!(c.is_nan());
3094 ///
3095 /// let (s, c) = Float::ZERO.sin_cos();
3096 /// assert_eq!(s.to_string(), "0.0");
3097 /// assert_eq!(c.to_string(), "1.0");
3098 ///
3099 /// let (s, c) = Float::NEGATIVE_ZERO.sin_cos();
3100 /// assert_eq!(s.to_string(), "-0.0");
3101 /// assert_eq!(c.to_string(), "1.0");
3102 ///
3103 /// let (s, c) = Float::from_unsigned_prec(1u32, 100).0.sin_cos();
3104 /// assert_eq!(s.to_string(), "0.84147098480789650665250232163005");
3105 /// assert_eq!(c.to_string(), "0.54030230586813971740093660744335");
3106 /// ```
3107 #[inline]
3108 fn sin_cos(self) -> (Self, Self) {
3109 let prec = self.significant_bits();
3110 let (s, c, _, _) = self.sin_cos_prec_round_ref(prec, Nearest);
3111 (s, c)
3112 }
3113}
3114
3115impl SinCos for &Float {
3116 type Output = Float;
3117
3118 /// Computes $\sin x$ and $\cos x$, the sine and cosine of a [`Float`], together, taking it by
3119 /// reference.
3120 ///
3121 /// See [`Float::sin_cos`]; this function behaves the same way.
3122 ///
3123 /// # Examples
3124 /// ```
3125 /// use malachite_base::num::arithmetic::traits::SinCos;
3126 /// use malachite_float::Float;
3127 ///
3128 /// let (s, c) = (&Float::from_unsigned_prec(1u32, 100).0).sin_cos();
3129 /// assert_eq!(s.to_string(), "0.84147098480789650665250232163005");
3130 /// assert_eq!(c.to_string(), "0.54030230586813971740093660744335");
3131 /// ```
3132 #[inline]
3133 fn sin_cos(self) -> (Float, Float) {
3134 let (s, c, _, _) = self.sin_cos_prec_round_ref(self.significant_bits(), Nearest);
3135 (s, c)
3136 }
3137}
3138
3139impl SinCosAssign for Float {
3140 /// Replaces a [`Float`] with its sine and writes its cosine to `cos`, rounding both results to
3141 /// the nearest value of the input's precision. The previous value of `cos` is discarded.
3142 ///
3143 /// See [`Float::sin_cos`]; this function behaves the same way.
3144 ///
3145 /// # Examples
3146 /// ```
3147 /// use malachite_base::num::arithmetic::traits::SinCosAssign;
3148 /// use malachite_base::num::basic::traits::NaN;
3149 /// use malachite_float::Float;
3150 ///
3151 /// let mut x = Float::from_unsigned_prec(1u32, 100).0;
3152 /// let mut c = Float::NAN;
3153 /// x.sin_cos_assign(&mut c);
3154 /// assert_eq!(x.to_string(), "0.84147098480789650665250232163005");
3155 /// assert_eq!(c.to_string(), "0.54030230586813971740093660744335");
3156 /// ```
3157 #[inline]
3158 fn sin_cos_assign(&mut self, cos: &mut Self) {
3159 let prec = self.significant_bits();
3160 self.sin_cos_prec_round_assign(cos, prec, Nearest);
3161 }
3162}
3163
3164/// Computes $\sin x$ and $\cos x$, the sine and cosine of a primitive float, together. Using this
3165/// function is more accurate than using the default `sin_cos` function or the ones provided by
3166/// `libm`.
3167///
3168/// The results are those of
3169/// [`primitive_float_sin`](crate::float::arithmetic::sin::primitive_float_sin) and
3170/// [`primitive_float_cos`](crate::float::arithmetic::cos::primitive_float_cos), but the argument
3171/// reduction and most of the work are shared, so this is faster than the two calls when both values
3172/// are needed.
3173///
3174/// $$
3175/// f(x) = (\sin x+\varepsilon_s, \cos x+\varepsilon_c).
3176/// $$
3177/// - If $x$ is not finite, $\varepsilon_s$ and $\varepsilon_c$ may be ignored or assumed to be 0.
3178/// - If $x$ is finite, then $|\varepsilon_s| < 2^{\lfloor\log_2 |\sin x|\rfloor-p}$ and
3179/// $|\varepsilon_c| < 2^{\lfloor\log_2 |\cos x|\rfloor-p}$, where $p$ is the precision of the
3180/// output (24 if `T` is a [`f32`] and 53 if `T` is a [`f64`]).
3181///
3182/// Special cases:
3183/// - $f(\text{NaN})=(\text{NaN},\text{NaN})$
3184/// - $f(\pm\infty)=(\text{NaN},\text{NaN})$
3185/// - $f(\pm0.0)=(\pm0.0,1.0)$
3186///
3187/// Overflow is not possible, since the results lie in $[-1, 1]$. The sine is subnormal only when
3188/// $x$ is, and then it is $x$ itself; the cosine is never subnormal. See
3189/// [`primitive_float_sin`](crate::float::arithmetic::sin::primitive_float_sin) and
3190/// [`primitive_float_cos`](crate::float::arithmetic::cos::primitive_float_cos).
3191///
3192/// # Worst-case complexity
3193/// Constant time and additional memory.
3194///
3195/// # Examples
3196/// ```
3197/// use malachite_base::num::float::NiceFloat;
3198/// use malachite_float::float::arithmetic::sin_cos::primitive_float_sin_cos;
3199///
3200/// let (s, c) = primitive_float_sin_cos(f32::NAN);
3201/// assert!(s.is_nan());
3202/// assert!(c.is_nan());
3203///
3204/// let (s, c) = primitive_float_sin_cos(0.0f32);
3205/// assert_eq!(NiceFloat(s), NiceFloat(0.0));
3206/// assert_eq!(NiceFloat(c), NiceFloat(1.0));
3207///
3208/// let (s, c) = primitive_float_sin_cos(1.0f32);
3209/// assert_eq!(NiceFloat(s), NiceFloat(0.84147096));
3210/// assert_eq!(NiceFloat(c), NiceFloat(0.5403023));
3211///
3212/// let (s, c) = primitive_float_sin_cos(1.0f64);
3213/// assert_eq!(NiceFloat(s), NiceFloat(0.8414709848078965));
3214/// assert_eq!(NiceFloat(c), NiceFloat(0.5403023058681398));
3215/// ```
3216#[inline]
3217#[allow(clippy::type_repetition_in_bounds)]
3218pub fn primitive_float_sin_cos<T: PrimitiveFloat>(x: T) -> (T, T)
3219where
3220 Float: From<T> + PartialOrd<T>,
3221 for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
3222{
3223 emulate_float_to_float_pair_fn(Float::sin_cos_prec, x)
3224}
3225
3226/// Computes $\sin x$ and $\cos x$, the sine and cosine of a [`Rational`], together, returning the
3227/// results as primitive floats.
3228///
3229/// The results are those of
3230/// [`primitive_float_sin_rational`](crate::float::arithmetic::sin::primitive_float_sin_rational)
3231/// and
3232/// [`primitive_float_cos_rational`](crate::float::arithmetic::cos::primitive_float_cos_rational),
3233/// but the rounding of the input, the argument reduction, and most of the work are shared, so this
3234/// is faster than the two calls when both values are needed.
3235///
3236/// $$
3237/// f(x) = (\sin x+\varepsilon_s, \cos x+\varepsilon_c),
3238/// $$
3239/// where $|\varepsilon_s| < 2^{\lfloor\log_2 |\sin x|\rfloor-p}$ and $|\varepsilon_c| <
3240/// 2^{\lfloor\log_2 |\cos x|\rfloor-p}$, and $p$ is the precision of the output (24 if `T` is a
3241/// [`f32`] and 53 if `T` is a [`f64`]).
3242///
3243/// Special cases:
3244/// - $f(0)=(0,1)$
3245///
3246/// Overflow is not possible, since the results lie in $[-1, 1]$. The sine underflows, to a
3247/// subnormal or to zero, when $x$ is tiny, since $\sin x$ is then very close to $x$; the cosine is
3248/// never subnormal. See
3249/// [`primitive_float_sin_rational`](crate::float::arithmetic::sin::primitive_float_sin_rational)
3250/// and
3251/// [`primitive_float_cos_rational`](crate::float::arithmetic::cos::primitive_float_cos_rational).
3252///
3253/// # Worst-case complexity
3254/// $T(m, e) = O((m+e) (\log (m+e))^2 \log\log (m+e))$
3255///
3256/// $M(m, e) = O((m+e) \log (m+e))$
3257///
3258/// where $T$ is time, $M$ is additional memory, $m$ is `x.significant_bits()`, and $e$ is
3259/// `x.floor_log_base_2_abs()` (taken as 0 when it is negative or $x = 0$): for $|x| \geq 2$ the
3260/// argument is reduced modulo $2\pi$, which needs $\pi$ to about $e$ bits.
3261///
3262/// # Examples
3263/// ```
3264/// use malachite_base::num::basic::traits::Zero;
3265/// use malachite_base::num::float::NiceFloat;
3266/// use malachite_float::float::arithmetic::sin_cos::primitive_float_sin_cos_rational;
3267/// use malachite_q::Rational;
3268///
3269/// let (s, c) = primitive_float_sin_cos_rational::<f64>(&Rational::ZERO);
3270/// assert_eq!(NiceFloat(s), NiceFloat(0.0));
3271/// assert_eq!(NiceFloat(c), NiceFloat(1.0));
3272///
3273/// let (s, c) = primitive_float_sin_cos_rational::<f64>(&Rational::from_unsigneds(1u8, 3));
3274/// assert_eq!(NiceFloat(s), NiceFloat(0.32719469679615226));
3275/// assert_eq!(NiceFloat(c), NiceFloat(0.9449569463147377));
3276///
3277/// let (s, c) = primitive_float_sin_cos_rational::<f32>(&Rational::from_unsigneds(1u8, 3));
3278/// assert_eq!(NiceFloat(s), NiceFloat(0.3271947));
3279/// assert_eq!(NiceFloat(c), NiceFloat(0.94495696));
3280/// ```
3281#[inline]
3282#[allow(clippy::type_repetition_in_bounds)]
3283pub fn primitive_float_sin_cos_rational<T: PrimitiveFloat>(x: &Rational) -> (T, T)
3284where
3285 Float: PartialOrd<T>,
3286 for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
3287{
3288 emulate_rational_to_float_pair_fn(Float::sin_cos_rational_prec_ref, x)
3289}
3290
3291/// Computes $\sin(2\pi x/u)$ and $\cos(2\pi x/u)$, the sine and cosine of a primitive float
3292/// measured in $u$ths of a turn (so that `u = 360` is degrees), together.
3293///
3294/// The results are those of
3295/// [`primitive_float_sin_with_period`](super::sin::primitive_float_sin_with_period) and
3296/// [`primitive_float_cos_with_period`](super::cos::primitive_float_cos_with_period), but the
3297/// argument reduction and most of the work are shared, so this is faster than the two calls when
3298/// both values are needed.
3299///
3300/// $$
3301/// f(x,u) = (\sin(2\pi x/u)+\varepsilon_s, \cos(2\pi x/u)+\varepsilon_c).
3302/// $$
3303/// - If $x$ is not finite or $u=0$, $\varepsilon_s$ and $\varepsilon_c$ may be ignored or assumed
3304/// to be 0.
3305/// - If $x$ is finite and $u\neq 0$, then $|\varepsilon_s| < 2^{\lfloor\log_2 |\sin(2\pi
3306/// x/u)|\rfloor-p}$ and $|\varepsilon_c| < 2^{\lfloor\log_2 |\cos(2\pi x/u)|\rfloor-p}$, where
3307/// $p$ is the precision of the output (24 if `T` is a [`f32`] and 53 if `T` is a [`f64`]).
3308///
3309/// Special cases:
3310/// - $f(\text{NaN},u)=(\text{NaN},\text{NaN})$
3311/// - $f(\pm\infty,u)=(\text{NaN},\text{NaN})$
3312/// - $f(x,0)=(\text{NaN},\text{NaN})$
3313/// - $f(\pm0.0,u)=(\pm0.0,1.0)$
3314/// - If $x/u$ is a multiple of $1/4$, both results are exact: the sine is $0.0$ with the sign of
3315/// $x$, $1$, or $-1$, and the cosine is $1$, $0.0$, or $-1$.
3316///
3317/// Overflow is not possible, since the results lie in $[-1, 1]$. The sine underflows, to a
3318/// subnormal or to zero, only when $2\pi x/u$ does, which takes a subnormal $x$ or a large $u$; the
3319/// cosine is never subnormal. See
3320/// [`primitive_float_sin_with_period`](super::sin::primitive_float_sin_with_period) and
3321/// [`primitive_float_cos_with_period`](super::cos::primitive_float_cos_with_period).
3322///
3323/// # Worst-case complexity
3324/// Constant time and additional memory.
3325///
3326/// # Examples
3327/// ```
3328/// use malachite_base::num::float::NiceFloat;
3329/// use malachite_float::float::arithmetic::sin_cos::primitive_float_sin_cos_with_period;
3330///
3331/// let (s, c) = primitive_float_sin_cos_with_period(f32::NAN, 360);
3332/// assert!(s.is_nan());
3333/// assert!(c.is_nan());
3334///
3335/// let (s, c) = primitive_float_sin_cos_with_period(1.0f32, 0);
3336/// assert!(s.is_nan());
3337/// assert!(c.is_nan());
3338///
3339/// let (s, c) = primitive_float_sin_cos_with_period(90.0f32, 360);
3340/// assert_eq!(NiceFloat(s), NiceFloat(1.0));
3341/// assert_eq!(NiceFloat(c), NiceFloat(0.0));
3342///
3343/// let (s, c) = primitive_float_sin_cos_with_period(30.0f64, 360);
3344/// assert_eq!(NiceFloat(s), NiceFloat(0.5));
3345/// assert_eq!(NiceFloat(c), NiceFloat(0.8660254037844386));
3346///
3347/// let (s, c) = primitive_float_sin_cos_with_period(1.0f32, 7);
3348/// assert_eq!(NiceFloat(s), NiceFloat(0.7818315));
3349/// assert_eq!(NiceFloat(c), NiceFloat(0.6234898));
3350///
3351/// let (s, c) = primitive_float_sin_cos_with_period(1.0f64, 7);
3352/// assert_eq!(NiceFloat(s), NiceFloat(0.7818314824680298));
3353/// assert_eq!(NiceFloat(c), NiceFloat(0.6234898018587335));
3354/// ```
3355#[inline]
3356#[allow(clippy::type_repetition_in_bounds)]
3357pub fn primitive_float_sin_cos_with_period<T: PrimitiveFloat>(x: T, u: u64) -> (T, T)
3358where
3359 Float: From<T> + PartialOrd<T>,
3360 for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
3361{
3362 emulate_float_to_float_pair_fn(|x, prec| Float::sin_cos_with_period_prec(x, u, prec), x)
3363}
3364
3365/// Computes $\sin(2\pi x/u)$ and $\cos(2\pi x/u)$, the sine and cosine of a [`Rational`] measured
3366/// in $u$ths of a turn (so that `u = 360` is degrees), together, returning the results as primitive
3367/// floats.
3368///
3369/// The results are those of
3370/// [`primitive_float_sin_with_period_rational`](super::sin::primitive_float_sin_with_period_rational)
3371/// and
3372/// [`primitive_float_cos_with_period_rational`](super::cos::primitive_float_cos_with_period_rational),
3373/// but the reduction of the fraction of a turn and most of the work are shared, so this is faster
3374/// than the two calls when both values are needed.
3375///
3376/// $$
3377/// f(x,u) = (\sin(2\pi x/u)+\varepsilon_s, \cos(2\pi x/u)+\varepsilon_c).
3378/// $$
3379/// - If $u=0$, $\varepsilon_s$ and $\varepsilon_c$ may be ignored or assumed to be 0.
3380/// - If $u\neq 0$, then $|\varepsilon_s| < 2^{\lfloor\log_2 |\sin(2\pi x/u)|\rfloor-p}$ and
3381/// $|\varepsilon_c| < 2^{\lfloor\log_2 |\cos(2\pi x/u)|\rfloor-p}$, where $p$ is the precision of
3382/// the output (24 if `T` is a [`f32`] and 53 if `T` is a [`f64`]).
3383///
3384/// Special cases:
3385/// - $f(x,0)=(\text{NaN},\text{NaN})$
3386/// - $f(0,u)=(0,1)$
3387/// - If $x/u$ is a multiple of $1/4$, both results are exact: the sine is $0.0$ with the sign of
3388/// $x$, $1$, or $-1$, and the cosine is $1$, $0.0$, or $-1$.
3389///
3390/// Overflow is not possible, since the results lie in $[-1, 1]$. The sine underflows, to a
3391/// subnormal or to zero, only when $2\pi x/u$ does, for a tiny $x/u$; the cosine is never
3392/// subnormal. See
3393/// [`primitive_float_sin_with_period_rational`](super::sin::primitive_float_sin_with_period_rational)
3394/// and
3395/// [`primitive_float_cos_with_period_rational`](super::cos::primitive_float_cos_with_period_rational).
3396///
3397/// # Worst-case complexity
3398/// $T(m) = O(m (\log m)^2 \log\log m)$
3399///
3400/// $M(m) = O(m \log m)$
3401///
3402/// where $T$ is time, $M$ is additional memory, and $m$ is `x.significant_bits()`: the fraction of
3403/// a turn is reduced modulo 1 exactly, so the magnitude of $x$ does not drive the cost.
3404///
3405/// # Examples
3406/// ```
3407/// use malachite_base::num::basic::traits::Zero;
3408/// use malachite_base::num::float::NiceFloat;
3409/// use malachite_float::float::arithmetic::sin_cos::primitive_float_sin_cos_with_period_rational;
3410/// use malachite_q::Rational;
3411///
3412/// let (s, c) = primitive_float_sin_cos_with_period_rational::<f64>(&Rational::ZERO, 0);
3413/// assert!(s.is_nan());
3414/// assert!(c.is_nan());
3415///
3416/// let (s, c) = primitive_float_sin_cos_with_period_rational::<f64>(&Rational::ZERO, 360);
3417/// assert_eq!(NiceFloat(s), NiceFloat(0.0));
3418/// assert_eq!(NiceFloat(c), NiceFloat(1.0));
3419///
3420/// // a twelfth of a turn: exactly 1/2, and sqrt(3)/2
3421/// let (s, c) =
3422/// primitive_float_sin_cos_with_period_rational::<f64>(&Rational::from_unsigneds(1u8, 12), 1);
3423/// assert_eq!(NiceFloat(s), NiceFloat(0.5));
3424/// assert_eq!(NiceFloat(c), NiceFloat(0.8660254037844386));
3425///
3426/// let (s, c) =
3427/// primitive_float_sin_cos_with_period_rational::<f32>(&Rational::from_unsigneds(1u8, 7), 1);
3428/// assert_eq!(NiceFloat(s), NiceFloat(0.7818315));
3429/// assert_eq!(NiceFloat(c), NiceFloat(0.6234898));
3430/// ```
3431#[inline]
3432#[allow(clippy::type_repetition_in_bounds)]
3433#[cfg_attr(dylint_lib = "malachite_lints", expect(long_lines))]
3434pub fn primitive_float_sin_cos_with_period_rational<T: PrimitiveFloat>(
3435 x: &Rational,
3436 u: u64,
3437) -> (T, T)
3438where
3439 Float: PartialOrd<T>,
3440 for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
3441{
3442 emulate_rational_to_float_pair_fn(
3443 |x, prec| Float::sin_cos_with_period_rational_prec_ref(x, u, prec),
3444 x,
3445 )
3446}
3447
3448/// Computes $\sin(\pi x)$ and $\cos(\pi x)$, the sine and cosine of a primitive float measured in
3449/// half-turns, together.
3450///
3451/// This is `primitive_float_sin_cos_with_period` with a period of 2: see
3452/// [`primitive_float_sin_cos_with_period`] for the error bounds and the special cases, with $u =
3453/// 2$. Multiples of $1/2$ give exact pairs from $\pm0.0$ (with the sign of the input for the sine)
3454/// and $\pm1$.
3455///
3456/// # Worst-case complexity
3457/// Constant time and additional memory.
3458///
3459/// # Examples
3460/// ```
3461/// use malachite_base::num::float::NiceFloat;
3462/// use malachite_float::float::arithmetic::sin_cos::primitive_float_sin_cos_pi;
3463///
3464/// let (s, c) = primitive_float_sin_cos_pi(f32::NAN);
3465/// assert!(s.is_nan());
3466/// assert!(c.is_nan());
3467///
3468/// let (s, c) = primitive_float_sin_cos_pi(0.5f32);
3469/// assert_eq!(NiceFloat(s), NiceFloat(1.0));
3470/// assert_eq!(NiceFloat(c), NiceFloat(0.0));
3471///
3472/// let (s, c) = primitive_float_sin_cos_pi(1.0f64);
3473/// assert_eq!(NiceFloat(s), NiceFloat(0.0));
3474/// assert_eq!(NiceFloat(c), NiceFloat(-1.0));
3475///
3476/// let (s, c) = primitive_float_sin_cos_pi(0.1f32);
3477/// assert_eq!(NiceFloat(s), NiceFloat(0.309017));
3478/// assert_eq!(NiceFloat(c), NiceFloat(0.95105654));
3479///
3480/// let (s, c) = primitive_float_sin_cos_pi(0.1f64);
3481/// assert_eq!(NiceFloat(s), NiceFloat(0.30901699437494745));
3482/// assert_eq!(NiceFloat(c), NiceFloat(0.9510565162951535));
3483/// ```
3484#[inline]
3485#[allow(clippy::type_repetition_in_bounds)]
3486pub fn primitive_float_sin_cos_pi<T: PrimitiveFloat>(x: T) -> (T, T)
3487where
3488 Float: From<T> + PartialOrd<T>,
3489 for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
3490{
3491 primitive_float_sin_cos_with_period(x, 2)
3492}
3493
3494/// Computes $\sin(\pi x)$ and $\cos(\pi x)$, the sine and cosine of a [`Rational`] measured in
3495/// half-turns, together, returning the results as primitive floats.
3496///
3497/// This is `primitive_float_sin_cos_with_period_rational` with a period of 2: see
3498/// [`primitive_float_sin_cos_with_period_rational`] for the error bounds, the special cases, and
3499/// the complexity, with $u = 2$.
3500///
3501/// # Worst-case complexity
3502/// $T(m) = O(m (\log m)^2 \log\log m)$
3503///
3504/// $M(m) = O(m \log m)$
3505///
3506/// where $T$ is time, $M$ is additional memory, and $m$ is `x.significant_bits()`.
3507///
3508/// # Examples
3509/// ```
3510/// use malachite_base::num::float::NiceFloat;
3511/// use malachite_float::float::arithmetic::sin_cos::primitive_float_sin_cos_pi_rational;
3512/// use malachite_q::Rational;
3513///
3514/// // a sixth of a half-turn: exactly 1/2, and sqrt(3)/2
3515/// let (s, c) = primitive_float_sin_cos_pi_rational::<f64>(&Rational::from_unsigneds(1u8, 6));
3516/// assert_eq!(NiceFloat(s), NiceFloat(0.5));
3517/// assert_eq!(NiceFloat(c), NiceFloat(0.8660254037844386));
3518///
3519/// let (s, c) = primitive_float_sin_cos_pi_rational::<f64>(&Rational::from_unsigneds(1u8, 7));
3520/// assert_eq!(NiceFloat(s), NiceFloat(0.4338837391175581));
3521/// assert_eq!(NiceFloat(c), NiceFloat(0.9009688679024191));
3522/// ```
3523#[inline]
3524#[allow(clippy::type_repetition_in_bounds)]
3525pub fn primitive_float_sin_cos_pi_rational<T: PrimitiveFloat>(x: &Rational) -> (T, T)
3526where
3527 Float: PartialOrd<T>,
3528 for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
3529{
3530 primitive_float_sin_cos_with_period_rational(x, 2)
3531}