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}