Skip to main content

malachite_float/float/arithmetic/
sinh_cosh.rs

1// Copyright © 2026 Mikhail Hogrefe
2//
3// Uses code adopted from the GNU MPFR Library.
4//
5//      Copyright 2001-2026 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
15use crate::InnerFloat::{Finite, Infinity, NaN, Zero};
16use crate::float::arithmetic::cosh::{
17    cosh_rational_helper, hyperbolic_approx, hyperbolic_can_round,
18};
19use crate::float::arithmetic::round_near_x::small_input_shortcut;
20use crate::float::arithmetic::sinh::sinh_rational_helper;
21use crate::float::conversion::string::set_str::overflow;
22use crate::{
23    Float, emulate_float_to_float_pair_fn, emulate_rational_to_float_pair_fn, floor_and_ceiling,
24};
25use core::cmp::Ordering::{self, Equal};
26use malachite_base::num::arithmetic::traits::{Abs, CeilingLogBase2, SinhCosh, SinhCoshAssign};
27use malachite_base::num::basic::floats::PrimitiveFloat;
28use malachite_base::num::basic::integers::PrimitiveInt;
29use malachite_base::num::basic::traits::{
30    Infinity as InfinityTrait, NaN as NaNTrait, One, Zero as ZeroTrait,
31};
32use malachite_base::num::conversion::traits::{ExactFrom, RoundingFrom};
33use malachite_base::num::logic::traits::SignificantBits;
34use malachite_base::rounding_modes::RoundingMode::{self, *};
35use malachite_nz::platform::Limb;
36use malachite_q::Rational;
37
38// This is mpfr_sinh_cosh from sinh_cosh.c, MPFR 4.2.2, where the input is finite and nonzero, with
39// two differences. First, MPFR has no small-input shortcut and does not raise its working precision
40// for the cancellation in exp(x) - exp(-x) at a small x, so for a tiny x its Ziv loop has to grow
41// the precision until it covers about -2 EXP(x) bits, computing exp(x) to about 2^30 bits for an x
42// near the smallest Float. Here the shortcuts of `sinh` and `cosh` are tried first, and the working
43// precision is raised as in `mpfr_sinh`. Second, MPFR's overflow branch relies on its extended
44// exponent range; here the near-overflow handling of `cosh` and `sinh` is used instead. Both
45// results have precision `prec`, where MPFR allows two precisions and works at the larger.
46fn sinh_cosh_prec_round_normal_ref(
47    x: &Float,
48    prec: u64,
49    rm: RoundingMode,
50) -> (Float, Float, Ordering, Ordering) {
51    assert_ne!(rm, Exact, "Inexact sinh_cosh");
52    let exp_x = i64::from(x.get_exponent().unwrap());
53    // For x small, sinh(x) = x + x^3/6 + ... has error below 2^(3 EXP(x) - 2), and cosh(x) = 1 +
54    // x^2/2 + ... has error below 2^(2 EXP(x)), so both may round from x and 1 alone. The cosine's
55    // bound is the weaker one, and its reference value 1 always rounds once the bound is small
56    // enough, so it decides, and is tried first.
57    let neg_two_exp = -(exp_x << 1);
58    if let Some((c, o_c)) = small_input_shortcut(&Float::ONE, neg_two_exp, 0, true, prec, rm)
59        && let Some((s, o_s)) = small_input_shortcut(x, neg_two_exp, 2, true, prec, rm)
60    {
61        return (s, c, o_s, o_c);
62    }
63    let positive = x.is_sign_positive();
64    let x_abs = x.abs();
65    // the optimal number of bits : see algorithms.ps
66    let mut working_prec = prec + prec.ceiling_log_base_2() + 4;
67    // If x is near 0, exp(x) - 1/exp(x) = 2*x+x^3/3+O(x^5), so the subtraction loses about -2
68    // EXP(x) bits.
69    if exp_x < 0 {
70        working_prec += u64::exact_from(neg_two_exp);
71    }
72    let mut increment = Limb::WIDTH;
73    loop {
74        let Some(approx) = hyperbolic_approx(&x_abs, working_prec) else {
75            // exp(|x|) / 2 overflows, and so do cosh(x) and sinh(x)
76            let (s, o_s) = overflow(positive, prec, rm);
77            let (c, o_c) = overflow(true, prec, rm);
78            return (s, c, o_s, o_c);
79        };
80        if hyperbolic_can_round(&approx.sinh, approx.sinh_bits, prec, rm)
81            && hyperbolic_can_round(&approx.cosh, approx.cosh_bits, prec, rm)
82        {
83            let sinh_abs = approx.sinh;
84            let (s, o_s) =
85                Float::from_float_prec_round(if positive { sinh_abs } else { -sinh_abs }, prec, rm);
86            let (c, o_c) = Float::from_float_prec_round(approx.cosh, prec, rm);
87            return (s, c, o_s, o_c);
88        }
89        working_prec += increment;
90        increment = working_prec >> 1;
91    }
92}
93
94// Computes sinh(x) and cosh(x) for a nonzero `Rational` x, rounded to precision `prec` with
95// rounding mode `rm`. Both are transcendental for every nonzero rational x, so neither result is
96// exact.
97fn sinh_cosh_rational_helper(
98    x: &Rational,
99    prec: u64,
100    rm: RoundingMode,
101) -> (Float, Float, Ordering, Ordering) {
102    assert_ne!(rm, Exact, "Inexact sinh_cosh");
103    let exp_x = x.floor_log_base_2_abs() + 1; // the MPFR-style exponent of x
104    // For an x small enough that the hyperbolic sine comes from its series (or underflows), both
105    // results come cheaply from the separate paths, which share no exponential: the hyperbolic
106    // cosine then rounds from 1, or, at a high precision, brackets a small x. This also covers
107    // every x too small to be a `Float`.
108    if exp_x < -1 && u64::exact_from(-exp_x) << 4 >= prec + 10 {
109        let (s, o_s) = sinh_rational_helper(x, prec, rm);
110        let (c, o_c) = cosh_rational_helper(x, prec, rm);
111        return (s, c, o_s, o_c);
112    }
113    // |x| >= 2^(MAX_EXPONENT - 1), so both results overflow
114    if exp_x >= Float::MAX_EXPONENT_I64 {
115        let (s, o_s) = overflow(*x > 0u32, prec, rm);
116        let (c, o_c) = overflow(true, prec, rm);
117        return (s, c, o_s, o_c);
118    }
119    // Bracket x between the Floats x_lo <= x <= x_hi, which have the sign of x since x is not
120    // small. sinh is increasing, and cosh is monotonic on any interval not containing 0, so the
121    // exact values lie between those at the two ends; increase the working precision until both
122    // pairs of ends round to the same results.
123    let mut working_prec = prec + 10;
124    let mut increment = Limb::WIDTH;
125    loop {
126        let (x_lo, x_o) = Float::from_rational_prec_round_ref(x, working_prec, Floor);
127        if x_o == Equal {
128            // x is exactly representable at `working_prec`
129            return sinh_cosh_prec_round_normal_ref(&x_lo, prec, rm);
130        }
131        let (x_lo, x_hi) = floor_and_ceiling((x_lo, x_o));
132        // The hyperbolic sine and cosine of a finite nonzero Float are never exact, so the
133        // orderings are `Less` or `Greater`, never `Equal`.
134        let (s_lo, c_lo, o_s_lo, o_c_lo) = sinh_cosh_prec_round_normal_ref(&x_lo, prec, rm);
135        let (s_hi, c_hi, o_s_hi, o_c_hi) = sinh_cosh_prec_round_normal_ref(&x_hi, prec, rm);
136        if o_s_lo == o_s_hi && o_c_lo == o_c_hi && s_lo == s_hi && c_lo == c_hi {
137            return (s_lo, c_lo, o_s_lo, o_c_lo);
138        }
139        working_prec += increment;
140        increment = working_prec >> 1;
141    }
142}
143
144impl Float {
145    /// Computes $\sinh x$ and $\cosh x$, the hyperbolic sine and cosine of a [`Float`], together,
146    /// rounding both results to the specified precision and with the specified rounding mode. The
147    /// [`Float`] is taken by value. Two [`Ordering`]s are also returned, indicating whether the
148    /// rounded hyperbolic sine and cosine are less than, equal to, or greater than the exact
149    /// values. Although `NaN`s are not comparable to any [`Float`], whenever this function returns
150    /// a `NaN` it also returns `Equal` for it.
151    ///
152    /// The results are the same as those of [`Float::sinh_prec_round`] and
153    /// [`Float::cosh_prec_round`], but they share a single exponential, so this is faster than the
154    /// two calls when both values are needed.
155    ///
156    /// See [`RoundingMode`] for a description of the possible rounding modes.
157    ///
158    /// $$
159    /// f(x,p,m) = (\sinh x+\varepsilon_s, \cosh x+\varepsilon_c).
160    /// $$
161    /// - If a result is infinite, zero, or `NaN`, its $\varepsilon$ may be ignored or assumed to be
162    ///   0.
163    /// - If the results are finite and nonzero and $m$ is not `Nearest`, then $|\varepsilon_s| <
164    ///   2^{\lfloor\log_2 |\sinh x|\rfloor-p+1}$ and $|\varepsilon_c| < 2^{\lfloor\log_2 \cosh
165    ///   x\rfloor-p+1}$.
166    /// - If the results are finite and nonzero and $m$ is `Nearest`, then $|\varepsilon_s| \leq
167    ///   2^{\lfloor\log_2 |\sinh x|\rfloor-p}$ and $|\varepsilon_c| \leq 2^{\lfloor\log_2 \cosh
168    ///   x\rfloor-p}$.
169    ///
170    /// If the outputs have a precision, it is `prec`.
171    ///
172    /// Special cases:
173    /// - $f(\text{NaN},p,m)=(\text{NaN},\text{NaN})$
174    /// - $f(\infty,p,m)=(\infty,\infty)$
175    /// - $f(-\infty,p,m)=(-\infty,\infty)$
176    /// - $f(\pm0.0,p,m)=(\pm0.0,1.0)$
177    ///
178    /// Overflow:
179    /// - Each result overflows exactly as [`Float::sinh_prec_round`] or [`Float::cosh_prec_round`]
180    ///   does, which happens when $|x|$ exceeds about $(2^{30}-1)\log 2$. See those functions for
181    ///   the values returned.
182    /// - Since $|\sinh x|\geq|x|$ and $\cosh x\geq 1$, neither result underflows.
183    ///
184    /// If you know you'll be using `Nearest`, consider using [`Float::sinh_cosh_prec`] instead. If
185    /// you know that your target precision is the precision of the input, consider using
186    /// [`Float::sinh_cosh_round`] instead. If both of these things are true, consider using
187    /// [`Float::sinh_cosh`] instead.
188    ///
189    /// # Worst-case complexity
190    /// $T(n, m) = O((n+m)^{3/2} \log (n+m) \log\log (n+m))$
191    ///
192    /// $M(n, m) = O((n+m) \log (n+m))$
193    ///
194    /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
195    /// `self.significant_bits()`: the exponential is computed at a working precision of `prec` plus
196    /// the bits lost to cancellation in the hyperbolic sine of a small input, which is at most
197    /// about the input's precision when the small-input shortcuts do not apply.
198    ///
199    /// # Panics
200    /// Panics if `rm` is `Exact` and `self` is finite and nonzero, since the hyperbolic sine and
201    /// cosine of a finite nonzero [`Float`] are never exactly representable, or if `prec` is zero.
202    ///
203    /// # Examples
204    /// ```
205    /// use malachite_base::rounding_modes::RoundingMode::*;
206    /// use malachite_float::Float;
207    /// use std::cmp::Ordering::*;
208    ///
209    /// let (s, c, o_s, o_c) = Float::from_unsigned_prec(1u32, 100)
210    ///     .0
211    ///     .sinh_cosh_prec_round(5, Floor);
212    /// assert_eq!(s.to_string(), "1.12");
213    /// assert_eq!(c.to_string(), "1.50");
214    /// assert_eq!(o_s, Less);
215    /// assert_eq!(o_c, Less);
216    ///
217    /// let (s, c, o_s, o_c) = Float::from_unsigned_prec(1u32, 100)
218    ///     .0
219    ///     .sinh_cosh_prec_round(5, Ceiling);
220    /// assert_eq!(s.to_string(), "1.19");
221    /// assert_eq!(c.to_string(), "1.56");
222    /// assert_eq!(o_s, Greater);
223    /// assert_eq!(o_c, Greater);
224    ///
225    /// let (s, c, o_s, o_c) = Float::from_unsigned_prec(1u32, 100)
226    ///     .0
227    ///     .sinh_cosh_prec_round(20, Nearest);
228    /// assert_eq!(s.to_string(), "1.1752014");
229    /// assert_eq!(c.to_string(), "1.5430813");
230    /// assert_eq!(o_s, Greater);
231    /// assert_eq!(o_c, Greater);
232    /// ```
233    #[inline]
234    pub fn sinh_cosh_prec_round(
235        self,
236        prec: u64,
237        rm: RoundingMode,
238    ) -> (Self, Self, Ordering, Ordering) {
239        self.sinh_cosh_prec_round_ref(prec, rm)
240    }
241
242    /// Computes $\sinh x$ and $\cosh x$, the hyperbolic sine and cosine of a [`Float`], together,
243    /// rounding both results to the specified precision and with the specified rounding mode. The
244    /// [`Float`] is taken by reference. Two [`Ordering`]s are also returned, indicating whether the
245    /// rounded hyperbolic sine and cosine are less than, equal to, or greater than the exact
246    /// values.
247    ///
248    /// See [`Float::sinh_cosh_prec_round`] for the error bounds, the special cases, overflow, and
249    /// the complexity; this function behaves the same way.
250    ///
251    /// # Panics
252    /// Panics if `rm` is `Exact` and `self` is finite and nonzero, since the hyperbolic sine and
253    /// cosine of a finite nonzero [`Float`] are never exactly representable, or if `prec` is zero.
254    ///
255    /// # Examples
256    /// ```
257    /// use malachite_base::rounding_modes::RoundingMode::*;
258    /// use malachite_float::Float;
259    /// use std::cmp::Ordering::*;
260    ///
261    /// let x = Float::from_unsigned_prec(1u32, 100).0;
262    /// let (s, c, o_s, o_c) = x.sinh_cosh_prec_round_ref(5, Floor);
263    /// assert_eq!(s.to_string(), "1.12");
264    /// assert_eq!(c.to_string(), "1.50");
265    /// assert_eq!(o_s, Less);
266    /// assert_eq!(o_c, Less);
267    ///
268    /// let (s, c, o_s, o_c) = x.sinh_cosh_prec_round_ref(20, Nearest);
269    /// assert_eq!(s.to_string(), "1.1752014");
270    /// assert_eq!(c.to_string(), "1.5430813");
271    /// assert_eq!(o_s, Greater);
272    /// assert_eq!(o_c, Greater);
273    /// ```
274    pub fn sinh_cosh_prec_round_ref(
275        &self,
276        prec: u64,
277        rm: RoundingMode,
278    ) -> (Self, Self, Ordering, Ordering) {
279        assert_ne!(prec, 0);
280        match &self.0 {
281            NaN => (Self::NAN, Self::NAN, Equal, Equal),
282            // sinh(±inf) = ±inf and cosh(±inf) = inf, exactly
283            Infinity { .. } => (self.clone(), Self::INFINITY, Equal, Equal),
284            // sinh(±0) = ±0 and cosh(±0) = 1, exactly
285            Zero { .. } => (self.clone(), Self::one_prec(prec), Equal, Equal),
286            Finite { .. } => sinh_cosh_prec_round_normal_ref(self, prec, rm),
287        }
288    }
289
290    /// Computes $\sinh x$ and $\cosh x$, the hyperbolic sine and cosine of a [`Float`], together,
291    /// rounding both results to the nearest value of the specified precision. The [`Float`] is
292    /// taken by value. Two [`Ordering`]s are also returned, indicating whether the rounded
293    /// hyperbolic sine and cosine are less than, equal to, or greater than the exact values.
294    ///
295    /// If a result is equidistant from two [`Float`]s with the specified precision, the [`Float`]
296    /// with fewer 1s in its binary expansion is chosen. See [`RoundingMode`] for a description of
297    /// the `Nearest` rounding mode.
298    ///
299    /// See [`Float::sinh_cosh_prec_round`] for the error bounds, the special cases, overflow, and
300    /// the complexity; this function behaves the same way with `Nearest`.
301    ///
302    /// If you want to use a rounding mode other than `Nearest`, consider using
303    /// [`Float::sinh_cosh_prec_round`] instead. If you know that your target precision is the
304    /// precision of the input, consider using [`Float::sinh_cosh`] instead.
305    ///
306    /// # Panics
307    /// Panics if `prec` is zero.
308    ///
309    /// # Examples
310    /// ```
311    /// use malachite_float::Float;
312    /// use std::cmp::Ordering::*;
313    ///
314    /// let (s, c, o_s, o_c) = Float::from_unsigned_prec(1u32, 100).0.sinh_cosh_prec(5);
315    /// assert_eq!(s.to_string(), "1.19");
316    /// assert_eq!(c.to_string(), "1.56");
317    /// assert_eq!(o_s, Greater);
318    /// assert_eq!(o_c, Greater);
319    ///
320    /// let (s, c, o_s, o_c) = Float::from_unsigned_prec(1u32, 100).0.sinh_cosh_prec(20);
321    /// assert_eq!(s.to_string(), "1.1752014");
322    /// assert_eq!(c.to_string(), "1.5430813");
323    /// assert_eq!(o_s, Greater);
324    /// assert_eq!(o_c, Greater);
325    /// ```
326    #[inline]
327    pub fn sinh_cosh_prec(self, prec: u64) -> (Self, Self, Ordering, Ordering) {
328        self.sinh_cosh_prec_round_ref(prec, Nearest)
329    }
330
331    /// Computes $\sinh x$ and $\cosh x$, the hyperbolic sine and cosine of a [`Float`], together,
332    /// rounding both results to the nearest value of the specified precision. The [`Float`] is
333    /// taken by reference. Two [`Ordering`]s are also returned, indicating whether the rounded
334    /// hyperbolic sine and cosine are less than, equal to, or greater than the exact values.
335    ///
336    /// If a result is equidistant from two [`Float`]s with the specified precision, the [`Float`]
337    /// with fewer 1s in its binary expansion is chosen. See [`RoundingMode`] for a description of
338    /// the `Nearest` rounding mode.
339    ///
340    /// See [`Float::sinh_cosh_prec_round`] for the error bounds, the special cases, overflow, and
341    /// the complexity; this function behaves the same way with `Nearest`.
342    ///
343    /// If you want to use a rounding mode other than `Nearest`, consider using
344    /// [`Float::sinh_cosh_prec_round_ref`] instead. If you know that your target precision is the
345    /// precision of the input, consider using `(&Float).sinh_cosh()` instead.
346    ///
347    /// # Panics
348    /// Panics if `prec` is zero.
349    ///
350    /// # Examples
351    /// ```
352    /// use malachite_float::Float;
353    /// use std::cmp::Ordering::*;
354    ///
355    /// let (s, c, o_s, o_c) = Float::from_unsigned_prec(1u32, 100).0.sinh_cosh_prec_ref(5);
356    /// assert_eq!(s.to_string(), "1.19");
357    /// assert_eq!(c.to_string(), "1.56");
358    /// assert_eq!(o_s, Greater);
359    /// assert_eq!(o_c, Greater);
360    ///
361    /// let (s, c, o_s, o_c) = Float::from_unsigned_prec(1u32, 100)
362    ///     .0
363    ///     .sinh_cosh_prec_ref(20);
364    /// assert_eq!(s.to_string(), "1.1752014");
365    /// assert_eq!(c.to_string(), "1.5430813");
366    /// assert_eq!(o_s, Greater);
367    /// assert_eq!(o_c, Greater);
368    /// ```
369    #[inline]
370    pub fn sinh_cosh_prec_ref(&self, prec: u64) -> (Self, Self, Ordering, Ordering) {
371        self.sinh_cosh_prec_round_ref(prec, Nearest)
372    }
373
374    /// Computes $\sinh x$ and $\cosh x$, the hyperbolic sine and cosine of a [`Float`], together,
375    /// rounding both results to the precision of the input and with the specified rounding mode.
376    /// The [`Float`] is taken by value. Two [`Ordering`]s are also returned, indicating whether the
377    /// rounded hyperbolic sine and cosine are less than, equal to, or greater than the exact
378    /// values.
379    ///
380    /// See [`Float::sinh_cosh_prec_round`] for the error bounds, the special cases, and overflow;
381    /// this function behaves the same way, with the precision of the input.
382    ///
383    /// If you want to specify an output precision, consider using [`Float::sinh_cosh_prec_round`]
384    /// instead. If you know you'll be using the `Nearest` rounding mode, consider using
385    /// [`Float::sinh_cosh`] instead.
386    ///
387    /// # Worst-case complexity
388    /// $T(n) = O(n^{3/2} \log n \log\log n)$
389    ///
390    /// $M(n) = O(n \log n)$
391    ///
392    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
393    ///
394    /// # Panics
395    /// Panics if `rm` is `Exact` and `self` is finite and nonzero, since the hyperbolic sine and
396    /// cosine of a finite nonzero [`Float`] are never exactly representable.
397    ///
398    /// # Examples
399    /// ```
400    /// use malachite_base::rounding_modes::RoundingMode::*;
401    /// use malachite_float::Float;
402    /// use std::cmp::Ordering::*;
403    ///
404    /// let (s, c, o_s, o_c) = Float::from_unsigned_prec(1u32, 5).0.sinh_cosh_round(Floor);
405    /// assert_eq!(s.to_string(), "1.12");
406    /// assert_eq!(c.to_string(), "1.50");
407    /// assert_eq!(o_s, Less);
408    /// assert_eq!(o_c, Less);
409    ///
410    /// let (s, c, o_s, o_c) = Float::from_unsigned_prec(1u32, 5)
411    ///     .0
412    ///     .sinh_cosh_round(Ceiling);
413    /// assert_eq!(s.to_string(), "1.19");
414    /// assert_eq!(c.to_string(), "1.56");
415    /// assert_eq!(o_s, Greater);
416    /// assert_eq!(o_c, Greater);
417    /// ```
418    #[inline]
419    pub fn sinh_cosh_round(self, rm: RoundingMode) -> (Self, Self, Ordering, Ordering) {
420        let prec = self.significant_bits();
421        self.sinh_cosh_prec_round_ref(prec, rm)
422    }
423
424    /// Computes $\sinh x$ and $\cosh x$, the hyperbolic sine and cosine of a [`Float`], together,
425    /// rounding both results to the precision of the input and with the specified rounding mode.
426    /// The [`Float`] is taken by reference. Two [`Ordering`]s are also returned, indicating whether
427    /// the rounded hyperbolic sine and cosine are less than, equal to, or greater than the exact
428    /// values.
429    ///
430    /// See [`Float::sinh_cosh_prec_round`] for the error bounds, the special cases, and overflow;
431    /// this function behaves the same way, with the precision of the input.
432    ///
433    /// If you want to specify an output precision, consider using
434    /// [`Float::sinh_cosh_prec_round_ref`] instead. If you know you'll be using the `Nearest`
435    /// rounding mode, consider using `(&Float).sinh_cosh()` instead.
436    ///
437    /// # Worst-case complexity
438    /// $T(n) = O(n^{3/2} \log n \log\log n)$
439    ///
440    /// $M(n) = O(n \log n)$
441    ///
442    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
443    ///
444    /// # Panics
445    /// Panics if `rm` is `Exact` and `self` is finite and nonzero, since the hyperbolic sine and
446    /// cosine of a finite nonzero [`Float`] are never exactly representable.
447    ///
448    /// # Examples
449    /// ```
450    /// use malachite_base::rounding_modes::RoundingMode::*;
451    /// use malachite_float::Float;
452    /// use std::cmp::Ordering::*;
453    ///
454    /// let (s, c, o_s, o_c) = Float::from_unsigned_prec(1u32, 5)
455    ///     .0
456    ///     .sinh_cosh_round_ref(Floor);
457    /// assert_eq!(s.to_string(), "1.12");
458    /// assert_eq!(c.to_string(), "1.50");
459    /// assert_eq!(o_s, Less);
460    /// assert_eq!(o_c, Less);
461    ///
462    /// let (s, c, o_s, o_c) = Float::from_unsigned_prec(1u32, 5)
463    ///     .0
464    ///     .sinh_cosh_round_ref(Ceiling);
465    /// assert_eq!(s.to_string(), "1.19");
466    /// assert_eq!(c.to_string(), "1.56");
467    /// assert_eq!(o_s, Greater);
468    /// assert_eq!(o_c, Greater);
469    /// ```
470    #[inline]
471    pub fn sinh_cosh_round_ref(&self, rm: RoundingMode) -> (Self, Self, Ordering, Ordering) {
472        self.sinh_cosh_prec_round_ref(self.significant_bits(), rm)
473    }
474
475    /// Replaces a [`Float`] with its hyperbolic sine and writes its hyperbolic cosine to `cosh`,
476    /// rounding both results to the specified precision and with the specified rounding mode. The
477    /// previous value of `cosh` is discarded. Two [`Ordering`]s are returned, indicating whether
478    /// the rounded hyperbolic sine and cosine are less than, equal to, or greater than the exact
479    /// values.
480    ///
481    /// See [`Float::sinh_cosh_prec_round`]; this function behaves the same way.
482    ///
483    /// # Panics
484    /// Panics if `rm` is `Exact` and `self` is finite and nonzero, since the hyperbolic sine and
485    /// cosine of a finite nonzero [`Float`] are never exactly representable, or if `prec` is zero.
486    ///
487    /// # Examples
488    /// ```
489    /// use malachite_base::num::basic::traits::NaN;
490    /// use malachite_base::rounding_modes::RoundingMode::*;
491    /// use malachite_float::Float;
492    /// use std::cmp::Ordering::*;
493    ///
494    /// let mut x = Float::from_unsigned_prec(1u32, 100).0;
495    /// let mut c = Float::NAN;
496    /// assert_eq!(
497    ///     x.sinh_cosh_prec_round_assign(&mut c, 5, Floor),
498    ///     (Less, Less)
499    /// );
500    /// assert_eq!(x.to_string(), "1.12");
501    /// assert_eq!(c.to_string(), "1.50");
502    /// ```
503    #[inline]
504    pub fn sinh_cosh_prec_round_assign(
505        &mut self,
506        cosh: &mut Self,
507        prec: u64,
508        rm: RoundingMode,
509    ) -> (Ordering, Ordering) {
510        let (s, c, o_s, o_c) = self.sinh_cosh_prec_round_ref(prec, rm);
511        *self = s;
512        *cosh = c;
513        (o_s, o_c)
514    }
515
516    /// Replaces a [`Float`] with its hyperbolic sine and writes its hyperbolic cosine to `cosh`,
517    /// rounding both results to the nearest value of the specified precision. The previous value of
518    /// `cosh` is discarded. Two [`Ordering`]s are returned, indicating whether the rounded
519    /// hyperbolic sine and cosine are less than, equal to, or greater than the exact values.
520    ///
521    /// See [`Float::sinh_cosh_prec`]; this function behaves the same way.
522    ///
523    /// # Panics
524    /// Panics if `prec` is zero.
525    ///
526    /// # Examples
527    /// ```
528    /// use malachite_base::num::basic::traits::NaN;
529    /// use malachite_float::Float;
530    /// use std::cmp::Ordering::*;
531    ///
532    /// let mut x = Float::from_unsigned_prec(1u32, 100).0;
533    /// let mut c = Float::NAN;
534    /// assert_eq!(x.sinh_cosh_prec_assign(&mut c, 20), (Greater, Greater));
535    /// assert_eq!(x.to_string(), "1.1752014");
536    /// assert_eq!(c.to_string(), "1.5430813");
537    /// ```
538    #[inline]
539    pub fn sinh_cosh_prec_assign(&mut self, cosh: &mut Self, prec: u64) -> (Ordering, Ordering) {
540        self.sinh_cosh_prec_round_assign(cosh, prec, Nearest)
541    }
542
543    /// Replaces a [`Float`] with its hyperbolic sine and writes its hyperbolic cosine to `cosh`,
544    /// rounding both results to the precision of the input and with the specified rounding mode.
545    /// The previous value of `cosh` is discarded. Two [`Ordering`]s are returned, indicating
546    /// whether the rounded hyperbolic sine and cosine are less than, equal to, or greater than the
547    /// exact values.
548    ///
549    /// See [`Float::sinh_cosh_round`] and [`Float::sinh_cosh_prec_round`]; this function behaves
550    /// the same way.
551    ///
552    /// # Panics
553    /// Panics if `rm` is `Exact` and `self` is finite and nonzero, since the hyperbolic sine and
554    /// cosine of a finite nonzero [`Float`] are never exactly representable.
555    ///
556    /// # Examples
557    /// ```
558    /// use malachite_base::num::basic::traits::NaN;
559    /// use malachite_base::rounding_modes::RoundingMode::*;
560    /// use malachite_float::Float;
561    /// use std::cmp::Ordering::*;
562    ///
563    /// let mut x = Float::from_unsigned_prec(1u32, 5).0;
564    /// let mut c = Float::NAN;
565    /// assert_eq!(x.sinh_cosh_round_assign(&mut c, Floor), (Less, Less));
566    /// assert_eq!(x.to_string(), "1.12");
567    /// assert_eq!(c.to_string(), "1.50");
568    /// ```
569    #[inline]
570    pub fn sinh_cosh_round_assign(
571        &mut self,
572        cosh: &mut Self,
573        rm: RoundingMode,
574    ) -> (Ordering, Ordering) {
575        let prec = self.significant_bits();
576        self.sinh_cosh_prec_round_assign(cosh, prec, rm)
577    }
578}
579
580impl Float {
581    /// Computes $\sinh x$ and $\cosh x$, the hyperbolic sine and cosine of a [`Rational`],
582    /// together, rounding both results to the specified precision and with the specified rounding
583    /// mode, and returning the results as [`Float`]s. The [`Rational`] is taken by value. Two
584    /// [`Ordering`]s are also returned, indicating whether the rounded hyperbolic sine and cosine
585    /// are less than, equal to, or greater than the exact values.
586    ///
587    /// The results are the same as those of [`Float::sinh_rational_prec_round`] and
588    /// [`Float::cosh_rational_prec_round`], but they share their exponentials, so this is faster
589    /// than the two calls when both values are needed.
590    ///
591    /// See [`RoundingMode`] for a description of the possible rounding modes.
592    ///
593    /// $$
594    /// f(x,p,m) = (\sinh x+\varepsilon_s, \cosh x+\varepsilon_c).
595    /// $$
596    /// - If $m$ is not `Nearest`, then $|\varepsilon_s| < 2^{\lfloor\log_2 |\sinh x|\rfloor-p+1}$
597    ///   and $|\varepsilon_c| < 2^{\lfloor\log_2 \cosh x\rfloor-p+1}$.
598    /// - If $m$ is `Nearest`, then $|\varepsilon_s| \leq 2^{\lfloor\log_2 |\sinh x|\rfloor-p}$ and
599    ///   $|\varepsilon_c| \leq 2^{\lfloor\log_2 \cosh x\rfloor-p}$.
600    ///
601    /// These bounds do not apply to a result that overflows or underflows; see below.
602    ///
603    /// The outputs have precision `prec`.
604    ///
605    /// Special cases:
606    /// - $f(0,p,m)=(0.0,1.0)$.
607    ///
608    /// Overflow and underflow:
609    /// - Each result overflows exactly as [`Float::sinh_rational_prec_round`] or
610    ///   [`Float::cosh_rational_prec_round`] does, which happens when $|x|$ exceeds about
611    ///   $(2^{30}-1)\log 2$. See those functions for the values returned.
612    /// - The hyperbolic sine underflows exactly as [`Float::sinh_rational_prec_round`] does, which
613    ///   requires an input of magnitude below $2^{-2^{30}}$; the hyperbolic cosine never
614    ///   underflows.
615    ///
616    /// If you know you'll be using `Nearest`, consider using [`Float::sinh_cosh_rational_prec`]
617    /// instead.
618    ///
619    /// # Worst-case complexity
620    /// $T(n, m) = O(n^{3/2} \log n \log\log n + m (\log m)^2 \log\log m)$
621    ///
622    /// $M(n, m) = O(n \log n + m \log m)$
623    ///
624    /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
625    /// `x.significant_bits()`.
626    ///
627    /// # Panics
628    /// Panics if `prec` is zero, or if `rm` is `Exact` but the results cannot be represented
629    /// exactly with the given precision (which is the case for every nonzero input).
630    ///
631    /// # Examples
632    /// ```
633    /// use malachite_base::rounding_modes::RoundingMode::*;
634    /// use malachite_float::Float;
635    /// use malachite_q::Rational;
636    /// use std::cmp::Ordering::*;
637    ///
638    /// let (s, c, o_s, o_c) =
639    ///     Float::sinh_cosh_rational_prec_round(Rational::from_unsigneds(3u8, 5), 5, Floor);
640    /// assert_eq!(s.to_string(), "0.625");
641    /// assert_eq!(c.to_string(), "1.12");
642    /// assert_eq!(o_s, Less);
643    /// assert_eq!(o_c, Less);
644    ///
645    /// let (s, c, o_s, o_c) =
646    ///     Float::sinh_cosh_rational_prec_round(Rational::from_signeds(-3i8, 5), 20, Ceiling);
647    /// assert_eq!(s.to_string(), "-0.63665295");
648    /// assert_eq!(c.to_string(), "1.1854668");
649    /// assert_eq!(o_s, Greater);
650    /// assert_eq!(o_c, Greater);
651    /// ```
652    #[allow(clippy::needless_pass_by_value)]
653    #[inline]
654    pub fn sinh_cosh_rational_prec_round(
655        x: Rational,
656        prec: u64,
657        rm: RoundingMode,
658    ) -> (Self, Self, Ordering, Ordering) {
659        Self::sinh_cosh_rational_prec_round_ref(&x, prec, rm)
660    }
661
662    /// Computes $\sinh x$ and $\cosh x$, the hyperbolic sine and cosine of a [`Rational`],
663    /// together, rounding both results to the specified precision and with the specified rounding
664    /// mode, and returning the results as [`Float`]s. The [`Rational`] is taken by reference. Two
665    /// [`Ordering`]s are also returned, indicating whether the rounded hyperbolic sine and cosine
666    /// are less than, equal to, or greater than the exact values.
667    ///
668    /// See [`Float::sinh_cosh_rational_prec_round`] for the error bounds, the special cases,
669    /// overflow and underflow, and the complexity; this function behaves the same way.
670    ///
671    /// # Panics
672    /// Panics if `prec` is zero, or if `rm` is `Exact` but the results cannot be represented
673    /// exactly with the given precision (which is the case for every nonzero input).
674    ///
675    /// # Examples
676    /// ```
677    /// use malachite_base::rounding_modes::RoundingMode::*;
678    /// use malachite_float::Float;
679    /// use malachite_q::Rational;
680    /// use std::cmp::Ordering::*;
681    ///
682    /// let (s, c, o_s, o_c) =
683    ///     Float::sinh_cosh_rational_prec_round_ref(&Rational::from_unsigneds(3u8, 5), 5, Floor);
684    /// assert_eq!(s.to_string(), "0.625");
685    /// assert_eq!(c.to_string(), "1.12");
686    /// assert_eq!(o_s, Less);
687    /// assert_eq!(o_c, Less);
688    /// ```
689    pub fn sinh_cosh_rational_prec_round_ref(
690        x: &Rational,
691        prec: u64,
692        rm: RoundingMode,
693    ) -> (Self, Self, Ordering, Ordering) {
694        assert_ne!(prec, 0);
695        if *x == 0u32 {
696            // sinh(0) = 0 and cosh(0) = 1, exactly
697            return (Self::ZERO, Self::one_prec(prec), Equal, Equal);
698        }
699        sinh_cosh_rational_helper(x, prec, rm)
700    }
701
702    /// Computes $\sinh x$ and $\cosh x$, the hyperbolic sine and cosine of a [`Rational`],
703    /// together, rounding both results to the nearest value of the specified precision, and
704    /// returning the results as [`Float`]s. The [`Rational`] is taken by value. Two [`Ordering`]s
705    /// are also returned, indicating whether the rounded hyperbolic sine and cosine are less than,
706    /// equal to, or greater than the exact values.
707    ///
708    /// If a result is equidistant from two [`Float`]s with the specified precision, the [`Float`]
709    /// with fewer 1s in its binary expansion is chosen. See [`RoundingMode`] for a description of
710    /// the `Nearest` rounding mode.
711    ///
712    /// See [`Float::sinh_cosh_rational_prec_round`] for the error bounds, the special cases,
713    /// overflow and underflow, and the complexity; this function behaves the same way with
714    /// `Nearest`.
715    ///
716    /// If you want to use a rounding mode other than `Nearest`, consider using
717    /// [`Float::sinh_cosh_rational_prec_round`] instead.
718    ///
719    /// # Panics
720    /// Panics if `prec` is zero.
721    ///
722    /// # Examples
723    /// ```
724    /// use malachite_float::Float;
725    /// use malachite_q::Rational;
726    /// use std::cmp::Ordering::*;
727    ///
728    /// let (s, c, o_s, o_c) = Float::sinh_cosh_rational_prec(Rational::from_unsigneds(3u8, 5), 20);
729    /// assert_eq!(s.to_string(), "0.63665390");
730    /// assert_eq!(c.to_string(), "1.1854649");
731    /// assert_eq!(o_s, Greater);
732    /// assert_eq!(o_c, Less);
733    /// ```
734    #[allow(clippy::needless_pass_by_value)]
735    #[inline]
736    pub fn sinh_cosh_rational_prec(x: Rational, prec: u64) -> (Self, Self, Ordering, Ordering) {
737        Self::sinh_cosh_rational_prec_round_ref(&x, prec, Nearest)
738    }
739
740    /// Computes $\sinh x$ and $\cosh x$, the hyperbolic sine and cosine of a [`Rational`],
741    /// together, rounding both results to the nearest value of the specified precision, and
742    /// returning the results as [`Float`]s. The [`Rational`] is taken by reference. Two
743    /// [`Ordering`]s are also returned, indicating whether the rounded hyperbolic sine and cosine
744    /// are less than, equal to, or greater than the exact values.
745    ///
746    /// If a result is equidistant from two [`Float`]s with the specified precision, the [`Float`]
747    /// with fewer 1s in its binary expansion is chosen. See [`RoundingMode`] for a description of
748    /// the `Nearest` rounding mode.
749    ///
750    /// See [`Float::sinh_cosh_rational_prec_round`] for the error bounds, the special cases,
751    /// overflow and underflow, and the complexity; this function behaves the same way with
752    /// `Nearest`.
753    ///
754    /// If you want to use a rounding mode other than `Nearest`, consider using
755    /// [`Float::sinh_cosh_rational_prec_round_ref`] instead.
756    ///
757    /// # Panics
758    /// Panics if `prec` is zero.
759    ///
760    /// # Examples
761    /// ```
762    /// use malachite_base::num::basic::traits::Zero;
763    /// use malachite_float::Float;
764    /// use malachite_q::Rational;
765    /// use std::cmp::Ordering::*;
766    ///
767    /// let (s, c, o_s, o_c) =
768    ///     Float::sinh_cosh_rational_prec_ref(&Rational::from_unsigneds(3u8, 5), 20);
769    /// assert_eq!(s.to_string(), "0.63665390");
770    /// assert_eq!(c.to_string(), "1.1854649");
771    /// assert_eq!(o_s, Greater);
772    /// assert_eq!(o_c, Less);
773    ///
774    /// let (s, c, o_s, o_c) = Float::sinh_cosh_rational_prec_ref(&Rational::ZERO, 10);
775    /// assert_eq!(s.to_string(), "0.0");
776    /// assert_eq!(c.to_string(), "1.0000");
777    /// assert_eq!(o_s, Equal);
778    /// assert_eq!(o_c, Equal);
779    /// ```
780    #[inline]
781    pub fn sinh_cosh_rational_prec_ref(
782        x: &Rational,
783        prec: u64,
784    ) -> (Self, Self, Ordering, Ordering) {
785        Self::sinh_cosh_rational_prec_round_ref(x, prec, Nearest)
786    }
787}
788
789impl SinhCosh for Float {
790    type Output = Self;
791
792    /// Computes $\sinh x$ and $\cosh x$, the hyperbolic sine and cosine of a [`Float`], together,
793    /// taking it by value.
794    ///
795    /// If the outputs have a precision, it is the precision of the input. If a result is
796    /// equidistant from two [`Float`]s with the specified precision, the [`Float`] with fewer 1s in
797    /// its binary expansion is chosen. See [`RoundingMode`] for a description of the `Nearest`
798    /// rounding mode.
799    ///
800    /// $$
801    /// f(x) = (\sinh x+\varepsilon_s, \cosh x+\varepsilon_c).
802    /// $$
803    /// - If a result is infinite, zero, or `NaN`, its $\varepsilon$ may be ignored or assumed to be
804    ///   0.
805    /// - If the results are finite and nonzero, then $|\varepsilon_s| < 2^{\lfloor\log_2 |\sinh
806    ///   x|\rfloor-p}$ and $|\varepsilon_c| < 2^{\lfloor\log_2 \cosh x\rfloor-p}$, where $p$ is the
807    ///   precision of the input.
808    ///
809    /// Special cases:
810    /// - $f(\text{NaN})=(\text{NaN},\text{NaN})$
811    /// - $f(\infty)=(\infty,\infty)$
812    /// - $f(-\infty)=(-\infty,\infty)$
813    /// - $f(\pm0.0)=(\pm0.0,1.0)$
814    ///
815    /// See [`Float::sinh_cosh_prec_round`] for overflow and the complexity.
816    ///
817    /// If you want to use a rounding mode other than `Nearest`, consider using
818    /// [`Float::sinh_cosh_round`] instead. If you want to specify an output precision, consider
819    /// using [`Float::sinh_cosh_prec`] instead. If you want both of these things, consider using
820    /// [`Float::sinh_cosh_prec_round`] instead.
821    ///
822    /// # Examples
823    /// ```
824    /// use malachite_base::num::arithmetic::traits::SinhCosh;
825    /// use malachite_base::num::basic::traits::{NaN, NegativeInfinity, NegativeZero};
826    /// use malachite_float::Float;
827    ///
828    /// let (s, c) = Float::NAN.sinh_cosh();
829    /// assert!(s.is_nan());
830    /// assert!(c.is_nan());
831    ///
832    /// let (s, c) = Float::NEGATIVE_INFINITY.sinh_cosh();
833    /// assert_eq!(s.to_string(), "-Infinity");
834    /// assert_eq!(c.to_string(), "Infinity");
835    ///
836    /// let (s, c) = Float::NEGATIVE_ZERO.sinh_cosh();
837    /// assert_eq!(s.to_string(), "-0.0");
838    /// assert_eq!(c.to_string(), "1.0");
839    ///
840    /// let (s, c) = Float::from_unsigned_prec(1u32, 100).0.sinh_cosh();
841    /// assert_eq!(s.to_string(), "1.1752011936438014568823818505953");
842    /// assert_eq!(c.to_string(), "1.5430806348152437784779056207575");
843    /// ```
844    #[inline]
845    fn sinh_cosh(self) -> (Self, Self) {
846        let prec = self.significant_bits();
847        let (s, c, _, _) = self.sinh_cosh_prec_round_ref(prec, Nearest);
848        (s, c)
849    }
850}
851
852impl SinhCosh for &Float {
853    type Output = Float;
854
855    /// Computes $\sinh x$ and $\cosh x$, the hyperbolic sine and cosine of a [`Float`], together,
856    /// taking it by reference.
857    ///
858    /// If the outputs have a precision, it is the precision of the input. If a result is
859    /// equidistant from two [`Float`]s with the specified precision, the [`Float`] with fewer 1s in
860    /// its binary expansion is chosen. See [`RoundingMode`] for a description of the `Nearest`
861    /// rounding mode.
862    ///
863    /// $$
864    /// f(x) = (\sinh x+\varepsilon_s, \cosh x+\varepsilon_c).
865    /// $$
866    /// - If a result is infinite, zero, or `NaN`, its $\varepsilon$ may be ignored or assumed to be
867    ///   0.
868    /// - If the results are finite and nonzero, then $|\varepsilon_s| < 2^{\lfloor\log_2 |\sinh
869    ///   x|\rfloor-p}$ and $|\varepsilon_c| < 2^{\lfloor\log_2 \cosh x\rfloor-p}$, where $p$ is the
870    ///   precision of the input.
871    ///
872    /// Special cases:
873    /// - $f(\text{NaN})=(\text{NaN},\text{NaN})$
874    /// - $f(\infty)=(\infty,\infty)$
875    /// - $f(-\infty)=(-\infty,\infty)$
876    /// - $f(\pm0.0)=(\pm0.0,1.0)$
877    ///
878    /// See [`Float::sinh_cosh_prec_round`] for overflow and the complexity.
879    ///
880    /// If you want to use a rounding mode other than `Nearest`, consider using
881    /// [`Float::sinh_cosh_round_ref`] instead. If you want to specify an output precision, consider
882    /// using [`Float::sinh_cosh_prec_ref`] instead. If you want both of these things, consider
883    /// using [`Float::sinh_cosh_prec_round_ref`] instead.
884    ///
885    /// # Examples
886    /// ```
887    /// use malachite_base::num::arithmetic::traits::SinhCosh;
888    /// use malachite_base::num::basic::traits::{NaN, NegativeInfinity, NegativeZero};
889    /// use malachite_float::Float;
890    ///
891    /// let (s, c) = (&Float::NAN).sinh_cosh();
892    /// assert!(s.is_nan());
893    /// assert!(c.is_nan());
894    ///
895    /// let (s, c) = (&Float::NEGATIVE_INFINITY).sinh_cosh();
896    /// assert_eq!(s.to_string(), "-Infinity");
897    /// assert_eq!(c.to_string(), "Infinity");
898    ///
899    /// let (s, c) = (&Float::NEGATIVE_ZERO).sinh_cosh();
900    /// assert_eq!(s.to_string(), "-0.0");
901    /// assert_eq!(c.to_string(), "1.0");
902    ///
903    /// let (s, c) = (&Float::from_unsigned_prec(1u32, 100).0).sinh_cosh();
904    /// assert_eq!(s.to_string(), "1.1752011936438014568823818505953");
905    /// assert_eq!(c.to_string(), "1.5430806348152437784779056207575");
906    /// ```
907    #[inline]
908    fn sinh_cosh(self) -> (Float, Float) {
909        let (s, c, _, _) = self.sinh_cosh_prec_round_ref(self.significant_bits(), Nearest);
910        (s, c)
911    }
912}
913
914impl SinhCoshAssign for Float {
915    /// Replaces a [`Float`] with its hyperbolic sine and writes its hyperbolic cosine to `cosh`,
916    /// rounding both results to the nearest value of the input's precision. The previous value of
917    /// `cosh` is discarded.
918    ///
919    /// See [`Float::sinh_cosh`]; this function behaves the same way.
920    ///
921    /// # Examples
922    /// ```
923    /// use malachite_base::num::arithmetic::traits::SinhCoshAssign;
924    /// use malachite_base::num::basic::traits::NaN;
925    /// use malachite_float::Float;
926    ///
927    /// let mut x = Float::from_unsigned_prec(1u32, 100).0;
928    /// let mut c = Float::NAN;
929    /// x.sinh_cosh_assign(&mut c);
930    /// assert_eq!(x.to_string(), "1.1752011936438014568823818505953");
931    /// assert_eq!(c.to_string(), "1.5430806348152437784779056207575");
932    /// ```
933    #[inline]
934    fn sinh_cosh_assign(&mut self, cosh: &mut Self) {
935        let prec = self.significant_bits();
936        self.sinh_cosh_prec_round_assign(cosh, prec, Nearest);
937    }
938}
939
940/// Computes $\sinh x$ and $\cosh x$, the hyperbolic sine and cosine of a primitive float, together.
941/// The results are correctly rounded.
942///
943/// The results are those of
944/// [`primitive_float_sinh`](crate::float::arithmetic::sinh::primitive_float_sinh) and
945/// [`primitive_float_cosh`](crate::float::arithmetic::cosh::primitive_float_cosh), but they share a
946/// single exponential, so this is faster than the two calls when both values are needed.
947///
948/// $$
949/// f(x) = (\sinh x+\varepsilon_s, \cosh x+\varepsilon_c).
950/// $$
951/// - If a result is infinite, zero, or `NaN`, its $\varepsilon$ may be ignored or assumed to be 0.
952/// - If the results are finite and nonzero, then $|\varepsilon_s| < 2^{\lfloor\log_2 |\sinh
953///   x|\rfloor-p}$ and $|\varepsilon_c| < 2^{\lfloor\log_2 \cosh x\rfloor-p}$, where $p$ is the
954///   precision of the output (typically 24 if `T` is a [`f32`] and 53 if `T` is a [`f64`], but less
955///   for a subnormal hyperbolic sine).
956///
957/// Special cases:
958/// - $f(\text{NaN})=(\text{NaN},\text{NaN})$
959/// - $f(\infty)=(\infty,\infty)$
960/// - $f(-\infty)=(-\infty,\infty)$
961/// - $f(\pm0.0)=(\pm0.0,1.0)$
962///
963/// Overflow is possible: an `x` of large magnitude gives infinite results. Neither result
964/// underflows. The hyperbolic sine is subnormal only when $x$ is, and then it is $x$ itself.
965///
966/// # Worst-case complexity
967/// Constant time and additional memory.
968///
969/// # Examples
970/// ```
971/// use malachite_base::num::float::NiceFloat;
972/// use malachite_float::float::arithmetic::sinh_cosh::primitive_float_sinh_cosh;
973///
974/// let (s, c) = primitive_float_sinh_cosh(f32::NAN);
975/// assert!(s.is_nan());
976/// assert!(c.is_nan());
977///
978/// let (s, c) = primitive_float_sinh_cosh(-0.0f32);
979/// assert_eq!(NiceFloat(s), NiceFloat(-0.0));
980/// assert_eq!(NiceFloat(c), NiceFloat(1.0));
981///
982/// let (s, c) = primitive_float_sinh_cosh(1.0f32);
983/// assert_eq!(NiceFloat(s), NiceFloat(1.1752012));
984/// assert_eq!(NiceFloat(c), NiceFloat(1.5430807));
985///
986/// let (s, c) = primitive_float_sinh_cosh(-1.0f64);
987/// assert_eq!(NiceFloat(s), NiceFloat(-1.1752011936438014));
988/// assert_eq!(NiceFloat(c), NiceFloat(1.5430806348152437));
989///
990/// let (s, c) = primitive_float_sinh_cosh(1000.0f64);
991/// assert_eq!(NiceFloat(s), NiceFloat(f64::INFINITY));
992/// assert_eq!(NiceFloat(c), NiceFloat(f64::INFINITY));
993/// ```
994#[inline]
995#[allow(clippy::type_repetition_in_bounds)]
996pub fn primitive_float_sinh_cosh<T: PrimitiveFloat>(x: T) -> (T, T)
997where
998    Float: From<T> + PartialOrd<T>,
999    for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
1000{
1001    emulate_float_to_float_pair_fn(Float::sinh_cosh_prec, x)
1002}
1003
1004/// Computes $\sinh x$ and $\cosh x$, the hyperbolic sine and cosine of a [`Rational`], together,
1005/// returning the results as primitive floats. The results are correctly rounded.
1006///
1007/// The results are those of
1008/// [`primitive_float_sinh_rational`](crate::float::arithmetic::sinh::primitive_float_sinh_rational)
1009/// and [`primitive_float_cosh_rational`](
1010/// crate::float::arithmetic::cosh::primitive_float_cosh_rational), but they share their
1011/// exponentials, so this is faster than the two calls when both values are needed.
1012///
1013/// $$
1014/// f(x) = (\sinh x+\varepsilon_s, \cosh x+\varepsilon_c).
1015/// $$
1016/// - If a result is infinite or zero, its $\varepsilon$ may be ignored or assumed to be 0.
1017/// - If the results are finite and nonzero, then $|\varepsilon_s| < 2^{\lfloor\log_2 |\sinh
1018///   x|\rfloor-p}$ and $|\varepsilon_c| < 2^{\lfloor\log_2 \cosh x\rfloor-p}$, where $p$ is the
1019///   precision of the output (typically 24 if `T` is a [`f32`] and 53 if `T` is a [`f64`], but less
1020///   for a subnormal hyperbolic sine).
1021///
1022/// Special cases:
1023/// - $f(0)=(0.0,1.0)$
1024///
1025/// Overflow is possible: an `x` of large magnitude gives infinite results. The hyperbolic sine of
1026/// an `x` of small enough magnitude underflows to `0.0` or `-0.0`; the hyperbolic cosine never
1027/// underflows.
1028///
1029/// # Worst-case complexity
1030/// $T(m) = O(m (\log m)^2 \log\log m)$
1031///
1032/// $M(m) = O(m \log m)$
1033///
1034/// where $T$ is time, $M$ is additional memory, and $m$ is `x.significant_bits()`.
1035///
1036/// # Examples
1037/// ```
1038/// use malachite_base::num::basic::traits::NegativeInfinity;
1039/// use malachite_base::num::float::NiceFloat;
1040/// use malachite_float::float::arithmetic::sinh_cosh::primitive_float_sinh_cosh_rational;
1041/// use malachite_q::Rational;
1042///
1043/// let (s, c) = primitive_float_sinh_cosh_rational::<f64>(&Rational::from_unsigneds(1u8, 3));
1044/// assert_eq!(NiceFloat(s), NiceFloat(0.3395405572561501));
1045/// assert_eq!(NiceFloat(c), NiceFloat(1.0560718678299394));
1046///
1047/// let (s, c) = primitive_float_sinh_cosh_rational::<f64>(&Rational::from(-10000));
1048/// assert_eq!(NiceFloat(s), NiceFloat(f64::NEGATIVE_INFINITY));
1049/// assert_eq!(NiceFloat(c), NiceFloat(f64::INFINITY));
1050/// ```
1051#[inline]
1052#[allow(clippy::type_repetition_in_bounds)]
1053pub fn primitive_float_sinh_cosh_rational<T: PrimitiveFloat>(x: &Rational) -> (T, T)
1054where
1055    Float: PartialOrd<T>,
1056    for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
1057{
1058    emulate_rational_to_float_pair_fn(Float::sinh_cosh_rational_prec_ref, x)
1059}