Skip to main content

malachite_float/float/arithmetic/
sech.rs

1// Copyright © 2026 Mikhail Hogrefe
2//
3// Uses code adopted from the GNU MPFR Library.
4//
5//      Copyright 2005-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::cos::{cos_rational_tiny, round_scaled_bracket};
17use crate::float::arithmetic::cosh::monotone_rational_via_floats;
18use crate::float::arithmetic::exp::one_neighbor;
19use crate::float::arithmetic::round_near_x::small_input_shortcut;
20use crate::float::arithmetic::sin::underflowed;
21use crate::float::arithmetic::tan::round_bracket_signed_by;
22use crate::float::arithmetic::tanh::cosh_bound;
23use crate::{Float, emulate_float_to_float_fn, emulate_rational_to_float_fn, floor_and_ceiling};
24use core::cmp::Ordering::{self, Equal};
25use malachite_base::fail_on_untested_path;
26use malachite_base::num::arithmetic::traits::{
27    Abs, CeilingLogBase2, Reciprocal, ReciprocalAssign, Sech, SechAssign,
28};
29use malachite_base::num::basic::floats::PrimitiveFloat;
30use malachite_base::num::basic::integers::PrimitiveInt;
31use malachite_base::num::basic::traits::{NaN as NaNTrait, One, Zero as ZeroTrait};
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::natural::arithmetic::float::round::float_can_round;
36use malachite_nz::platform::Limb;
37use malachite_q::Rational;
38
39// Beyond this |x|, sech(x) < 2 exp(-|x|) < 2^(MIN_EXPONENT - 2) = 2^(-2^30 - 1), half the smallest
40// positive Float, since (2^30 + 2) log(2) = 744261119.35... |csch(x)| = 2 exp(-|x|) / (1 -
41// exp(-2|x|)) exceeds 2 exp(-|x|) only by a negligible factor, so the same threshold serves it.
42pub(crate) const RECIPROCAL_HYPERBOLIC_UNDERFLOW_THRESHOLD: u32 = 744261120;
43
44// Computes sech(x) (if `plus`) or csch(x) (if not) for a finite x with 2^29 <= |x| = `x_abs` <
45// `RECIPROCAL_HYPERBOLIC_UNDERFLOW_THRESHOLD`, the result being negative if `negative`. MPFR
46// computes 1 / cosh(x) or 1 / sinh(x) in its extended exponent range, and declares underflow when
47// the denominator overflows that range. In Malachite's exponent range, cosh(x) and sinh(x) overflow
48// at 2^(2^30 - 1), while their reciprocals stay representable down to 2^(-2^30 - 1), so for x in a
49// window of width about 2 log(2) the denominator overflows but the result does not; and a result
50// near the bottom of the range must be rounded with the underflow rules. So the result 2 exp(-|x|)
51// / (1 ± exp(-2|x|)) is computed from a = exp(-|x|/2), which is representable, scaled by an exact
52// power of 2 into [1/2, 1]: with A = a 2^S, it is 2^(1 - 2S) A^2 / (1 ± a^4). A^2 is bracketed
53// with directed roundings, and the factor is absorbed by nudging one end by an ulp: for sech, 1 -
54// 2^(-4S) < 1 / (1 + a^4) < 1 moves the lower end down, and for csch, 1 < 1 / (1 - a^4) < 1 + 2^(1
55// - 4S) moves the upper end up. The bracket is then rounded with the final scaling by 2^(1 - 2S).
56fn reciprocal_hyperbolic_scaled(
57    x_abs: &Float,
58    negative: bool,
59    plus: bool,
60    prec: u64,
61    rm: RoundingMode,
62) -> (Float, Ordering) {
63    let neg_half_x = -(x_abs >> 1u32);
64    let mut working_prec = prec + prec.ceiling_log_base_2() + 10;
65    let mut increment = Limb::WIDTH;
66    loop {
67        // exp(-|x|/2) is transcendental, so it is not exact
68        let (a_lo, a_hi) = floor_and_ceiling(neg_half_x.exp_prec_round_ref(working_prec, Floor));
69        let s = -i64::from(a_lo.get_exponent().unwrap());
70        let mut lo = (a_lo << s).square_round(Floor).0;
71        let mut hi = (a_hi << s).square_round(Ceiling).0;
72        // a < 2^(-S), so a^4 < 2^(-4S)
73        let four_s = u64::exact_from(s << 2);
74        if working_prec + 2 < four_s {
75            // 1 ulp is at least the value times 2^(-working_prec), more than it times 2^(1 - 4S)
76            if plus {
77                lo.decrement();
78            } else {
79                hi.increment();
80            }
81        } else {
82            // only reachable beyond about 2^30 bits of precision
83            fail_on_untested_path("reciprocal_hyperbolic_scaled, working precision beyond 4S");
84            if plus {
85                lo.mul_prec_round_assign(one_neighbor(four_s, false), working_prec, Floor);
86            } else {
87                hi.mul_prec_round_assign(one_neighbor(four_s - 1, true), working_prec, Ceiling);
88            }
89        }
90        let (lo, hi) = if negative { (-hi, -lo) } else { (lo, hi) };
91        if let Some(result) = round_scaled_bracket(&lo, &hi, 1 - (s << 1), prec, rm) {
92            return result;
93        }
94        working_prec += increment;
95        increment = working_prec >> 1;
96    }
97}
98
99// Computes sech(x) (if `plus`) or csch(x) (if not) for a finite x whose exponent exceeds 29, so
100// that |x| >= 2^29, returning `None` for any smaller x: past
101// `RECIPROCAL_HYPERBOLIC_UNDERFLOW_THRESHOLD` the result underflows, and below it the scaled path
102// computes it.
103pub(crate) fn reciprocal_hyperbolic_large(
104    x: &Float,
105    plus: bool,
106    prec: u64,
107    rm: RoundingMode,
108) -> Option<(Float, Ordering)> {
109    if x.get_exponent().unwrap() <= 29 {
110        return None;
111    }
112    let negative = !plus && x.is_sign_negative();
113    let x_abs = x.abs();
114    Some(if x_abs >= RECIPROCAL_HYPERBOLIC_UNDERFLOW_THRESHOLD {
115        underflowed(!negative, prec, rm)
116    } else {
117        reciprocal_hyperbolic_scaled(&x_abs, negative, plus, prec, rm)
118    })
119}
120
121// This is mpfr_sech from sech.c (an instantiation of gen_inverse.h), MPFR 4.2.2, where the input is
122// finite and nonzero, with the scaled path for large inputs.
123fn sech_prec_round_normal_ref(x: &Float, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
124    assert_ne!(rm, Exact, "Inexact sech");
125    let exp_x = i64::from(x.get_exponent().unwrap());
126    // for x near 0, sech(x) = 1 - x^2/2 + ..., more precisely |sech(x)-1| <= x^2/2 for |x| <= 1.
127    // The tiny action is the same as for cos(x).
128    //
129    // MPFR_FAST_COMPUTE_IF_SMALL_INPUT(y, __gmpfr_one, -2 * MPFR_GET_EXP (x), 1, 0, r, ...)
130    if let Some(result) = small_input_shortcut(&Float::ONE, -(exp_x << 1), 1, false, prec, rm) {
131        return result;
132    }
133    if let Some(result) = reciprocal_hyperbolic_large(x, true, prec, rm) {
134        return result;
135    }
136    // |x| < 2^29, so cosh(x) < exp(2^29) < 2^(2^30 - 1) cannot overflow, and sech(x) > 2^(-2^30) is
137    // well above the bottom of the exponent range.
138    let mut working_prec = prec + prec.ceiling_log_base_2() + 3;
139    let mut increment = Limb::WIDTH;
140    loop {
141        // the cosh has an error below 1 ulp, and rounding toward zero fixes its sign
142        let mut sech_x = x.cosh_prec_round_ref(working_prec, Down).0;
143        sech_x.reciprocal_assign();
144        // the error is less than c_w + 2*c_u*k_u (see algorithms.tex), where c_w = 1/2, c_u = 1
145        // since the cosh was rounded toward zero, thus 1/2 + 2 < 4
146        if float_can_round(
147            sech_x.significand_ref().unwrap(),
148            working_prec - 2,
149            prec,
150            rm,
151        ) {
152            return Float::from_float_prec_round(sech_x, prec, rm);
153        }
154        working_prec += increment;
155        increment = working_prec >> 1;
156    }
157}
158
159// Computes sech(x) for a nonzero `Rational` x, rounded to precision `prec` with rounding mode `rm`.
160// sech(x) is transcendental for every nonzero rational x, so the result is never exact.
161fn sech_rational_helper(x: &Rational, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
162    assert_ne!(rm, Exact, "Inexact sech");
163    let exp_x = x.floor_log_base_2_abs() + 1; // the MPFR-style exponent of x
164    // 0 < 1 - sech(x) < x^2/2 < 2^(2 exp_x - 1): when that is at most 2^(-prec - 1), half an ulp
165    // below 1, sech(x) rounds to 1, or to its predecessor for rounding toward zero, as cos(x) does.
166    if 1 - (exp_x << 1) > i64::exact_from(prec) {
167        return cos_rational_tiny(prec, rm);
168    }
169    // A small x is handled by bracketing sech(x) = 1 / cosh(x) with series bounds on cosh(x). This
170    // also covers every remaining x too small to be a `Float`.
171    if exp_x < -1 && u64::exact_from(-exp_x) << 4 >= prec + 10 {
172        return hyperbolic_series_quotient(x, false, None, cosh_bound, prec, rm);
173    }
174    let x_abs = x.abs();
175    if x_abs >= RECIPROCAL_HYPERBOLIC_UNDERFLOW_THRESHOLD {
176        return underflowed(true, prec, rm);
177    }
178    // sech is even and decreasing on [0, infinity), so bracket |x| between the Floats x_lo <= |x|
179    // <= x_hi, take the hyperbolic secant of both, and increase the working precision until the two
180    // round to the same result, which the exact sech(x), lying between them, must then share.
181    monotone_rational_via_floats(&x_abs, prec, rm, sech_prec_round_normal_ref)
182}
183
184// A bound on a hyperbolic function g for |t| < 1/2, from below, or from above if `away`, to within
185// a relative 2^-(w+3): `cosh_bound` or `sinh_bound`.
186pub(crate) type HyperbolicBound = fn(&Rational, u64, bool) -> Rational;
187
188// Computes f(x)/g(x), or 1/g(x) if `numerator` is `None`, for a nonzero `Rational` x small enough
189// that the series of f and g converge in a few terms, where `numerator` and `denominator` bound f
190// and g. The quotient at |x| is bracketed by quotients of the bounds, negated if `negative`, and
191// the bracket is tightened until both ends round the same way. This serves sech (1/cosh), csch
192// (1/sinh), and coth (cosh/sinh), and covers every x too small to be a `Float`.
193pub(crate) fn hyperbolic_series_quotient(
194    x: &Rational,
195    negative: bool,
196    numerator: Option<HyperbolicBound>,
197    denominator: HyperbolicBound,
198    prec: u64,
199    rm: RoundingMode,
200) -> (Float, Ordering) {
201    let ax = x.abs();
202    let mut w = prec + 10;
203    let mut increment = Limb::WIDTH;
204    loop {
205        let d_lo = denominator(&ax, w, false);
206        let d_hi = denominator(&ax, w, true);
207        let (lo, hi) = match numerator {
208            None => (d_hi.reciprocal(), d_lo.reciprocal()),
209            Some(numerator) => (
210                numerator(&ax, w, false) / d_hi,
211                numerator(&ax, w, true) / d_lo,
212            ),
213        };
214        if let Some(result) = round_bracket_signed_by(negative, lo, hi, prec, rm) {
215            return result;
216        }
217        w += increment;
218        increment = w >> 1;
219    }
220}
221
222impl Float {
223    /// Computes $\operatorname{sech} x$, the hyperbolic secant of a [`Float`], rounding the result
224    /// to the specified precision and with the specified rounding mode. The [`Float`] is taken by
225    /// value. An [`Ordering`] is also returned, indicating whether the rounded hyperbolic secant is
226    /// less than, equal to, or greater than the exact hyperbolic secant. Although `NaN`s are not
227    /// comparable to any [`Float`], whenever this function returns a `NaN` it also returns `Equal`.
228    ///
229    /// See [`RoundingMode`] for a description of the possible rounding modes.
230    ///
231    /// $$
232    /// f(x,p,m) = \operatorname{sech} x+\varepsilon.
233    /// $$
234    /// - If $\operatorname{sech} x$ is zero or `NaN`, $\varepsilon$ may be ignored or assumed to be
235    ///   0.
236    /// - If $\operatorname{sech} x$ is nonzero, and $m$ is not `Nearest`, then $|\varepsilon| <
237    ///   2^{\lfloor\log_2 \operatorname{sech} x\rfloor-p+1}$.
238    /// - If $\operatorname{sech} x$ is nonzero, and $m$ is `Nearest`, then $|\varepsilon| \leq
239    ///   2^{\lfloor\log_2 \operatorname{sech} x\rfloor-p}$.
240    ///
241    /// If the output has a precision, it is `prec`.
242    ///
243    /// Special cases:
244    /// - $f(\text{NaN},p,m)=\text{NaN}$
245    /// - $f(\infty,p,m)=0.0$
246    /// - $f(-\infty,p,m)=0.0$
247    /// - $f(\pm0.0,p,m)=1.0$
248    ///
249    /// Overflow and underflow:
250    /// - Since $\operatorname{sech} x\leq 1$, the result never overflows.
251    /// - If $0<f(x,p,m)<2^{-2^{30}}$, and $m$ is `Floor` or `Down`, $0.0$ is returned instead.
252    /// - If $0<f(x,p,m)<2^{-2^{30}}$, and $m$ is `Ceiling` or `Up`, $2^{-2^{30}}$ is returned
253    ///   instead.
254    /// - If $0<f(x,p,m)\leq2^{-2^{30}-1}$, and $m$ is `Nearest`, $0.0$ is returned instead.
255    /// - If $2^{-2^{30}-1}<f(x,p,m)<2^{-2^{30}}$, and $m$ is `Nearest`, $2^{-2^{30}}$ is returned
256    ///   instead.
257    ///
258    /// Underflow happens for inputs of magnitude above about $7.4\times10^8$.
259    ///
260    /// If you know you'll be using `Nearest`, consider using [`Float::sech_prec`] instead. If you
261    /// know that your target precision is the precision of the input, consider using
262    /// [`Float::sech_round`] instead. If both of these things are true, consider using
263    /// [`Float::sech`] instead.
264    ///
265    /// # Worst-case complexity
266    /// $T(n, m) = O(n^{3/2} \log n \log\log n + m)$
267    ///
268    /// $M(n, m) = O(n \log n + m)$
269    ///
270    /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
271    /// `self.significant_bits()`.
272    ///
273    /// # Panics
274    /// Panics if `rm` is `Exact` and `self` is finite and nonzero, since the hyperbolic secant of a
275    /// finite nonzero [`Float`] is never exactly representable, or if `prec` is zero.
276    ///
277    /// # Examples
278    /// ```
279    /// use malachite_base::rounding_modes::RoundingMode::*;
280    /// use malachite_float::Float;
281    /// use std::cmp::Ordering::*;
282    ///
283    /// let (c, o) = Float::from_unsigned_prec(1u32, 100)
284    ///     .0
285    ///     .sech_prec_round(5, Floor);
286    /// assert_eq!(c.to_string(), "0.625");
287    /// assert_eq!(o, Less);
288    ///
289    /// let (c, o) = Float::from_unsigned_prec(1u32, 100)
290    ///     .0
291    ///     .sech_prec_round(5, Ceiling);
292    /// assert_eq!(c.to_string(), "0.656");
293    /// assert_eq!(o, Greater);
294    ///
295    /// let (c, o) = Float::from_unsigned_prec(1u32, 100)
296    ///     .0
297    ///     .sech_prec_round(5, Nearest);
298    /// assert_eq!(c.to_string(), "0.656");
299    /// assert_eq!(o, Greater);
300    ///
301    /// let (c, o) = Float::from_unsigned_prec(1u32, 100)
302    ///     .0
303    ///     .sech_prec_round(20, Floor);
304    /// assert_eq!(c.to_string(), "0.64805412");
305    /// assert_eq!(o, Less);
306    ///
307    /// let (c, o) = Float::from_unsigned_prec(1u32, 100)
308    ///     .0
309    ///     .sech_prec_round(20, Ceiling);
310    /// assert_eq!(c.to_string(), "0.64805508");
311    /// assert_eq!(o, Greater);
312    ///
313    /// let (c, o) = Float::from_unsigned_prec(1u32, 100)
314    ///     .0
315    ///     .sech_prec_round(20, Nearest);
316    /// assert_eq!(c.to_string(), "0.64805412");
317    /// assert_eq!(o, Less);
318    /// ```
319    #[inline]
320    pub fn sech_prec_round(self, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
321        self.sech_prec_round_ref(prec, rm)
322    }
323
324    /// Computes $\operatorname{sech} x$, the hyperbolic secant of a [`Float`], rounding the result
325    /// to the specified precision and with the specified rounding mode. The [`Float`] is taken by
326    /// reference. An [`Ordering`] is also returned, indicating whether the rounded hyperbolic
327    /// secant is less than, equal to, or greater than the exact hyperbolic secant. Although `NaN`s
328    /// are not comparable to any [`Float`], whenever this function returns a `NaN` it also returns
329    /// `Equal`.
330    ///
331    /// See [`RoundingMode`] for a description of the possible rounding modes.
332    ///
333    /// $$
334    /// f(x,p,m) = \operatorname{sech} x+\varepsilon.
335    /// $$
336    /// - If $\operatorname{sech} x$ is zero or `NaN`, $\varepsilon$ may be ignored or assumed to be
337    ///   0.
338    /// - If $\operatorname{sech} x$ is nonzero, and $m$ is not `Nearest`, then $|\varepsilon| <
339    ///   2^{\lfloor\log_2 \operatorname{sech} x\rfloor-p+1}$.
340    /// - If $\operatorname{sech} x$ is nonzero, and $m$ is `Nearest`, then $|\varepsilon| \leq
341    ///   2^{\lfloor\log_2 \operatorname{sech} x\rfloor-p}$.
342    ///
343    /// If the output has a precision, it is `prec`.
344    ///
345    /// Special cases:
346    /// - $f(\text{NaN},p,m)=\text{NaN}$
347    /// - $f(\infty,p,m)=0.0$
348    /// - $f(-\infty,p,m)=0.0$
349    /// - $f(\pm0.0,p,m)=1.0$
350    ///
351    /// Overflow and underflow:
352    /// - Since $\operatorname{sech} x\leq 1$, the result never overflows.
353    /// - If $0<f(x,p,m)<2^{-2^{30}}$, and $m$ is `Floor` or `Down`, $0.0$ is returned instead.
354    /// - If $0<f(x,p,m)<2^{-2^{30}}$, and $m$ is `Ceiling` or `Up`, $2^{-2^{30}}$ is returned
355    ///   instead.
356    /// - If $0<f(x,p,m)\leq2^{-2^{30}-1}$, and $m$ is `Nearest`, $0.0$ is returned instead.
357    /// - If $2^{-2^{30}-1}<f(x,p,m)<2^{-2^{30}}$, and $m$ is `Nearest`, $2^{-2^{30}}$ is returned
358    ///   instead.
359    ///
360    /// Underflow happens for inputs of magnitude above about $7.4\times10^8$.
361    ///
362    /// If you know you'll be using `Nearest`, consider using [`Float::sech_prec_ref`] instead. If
363    /// you know that your target precision is the precision of the input, consider using
364    /// [`Float::sech_round_ref`] instead. If both of these things are true, consider using
365    /// `(&Float).sech()` instead.
366    ///
367    /// # Worst-case complexity
368    /// $T(n, m) = O(n^{3/2} \log n \log\log n + m)$
369    ///
370    /// $M(n, m) = O(n \log n + m)$
371    ///
372    /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
373    /// `self.significant_bits()`.
374    ///
375    /// # Panics
376    /// Panics if `rm` is `Exact` and `self` is finite and nonzero, since the hyperbolic secant of a
377    /// finite nonzero [`Float`] is never exactly representable, or if `prec` is zero.
378    ///
379    /// # Examples
380    /// ```
381    /// use malachite_base::rounding_modes::RoundingMode::*;
382    /// use malachite_float::Float;
383    /// use std::cmp::Ordering::*;
384    ///
385    /// let (c, o) = Float::from_unsigned_prec(1u32, 100)
386    ///     .0
387    ///     .sech_prec_round_ref(5, Floor);
388    /// assert_eq!(c.to_string(), "0.625");
389    /// assert_eq!(o, Less);
390    ///
391    /// let (c, o) = Float::from_unsigned_prec(1u32, 100)
392    ///     .0
393    ///     .sech_prec_round_ref(5, Ceiling);
394    /// assert_eq!(c.to_string(), "0.656");
395    /// assert_eq!(o, Greater);
396    ///
397    /// let (c, o) = Float::from_unsigned_prec(1u32, 100)
398    ///     .0
399    ///     .sech_prec_round_ref(5, Nearest);
400    /// assert_eq!(c.to_string(), "0.656");
401    /// assert_eq!(o, Greater);
402    ///
403    /// let (c, o) = Float::from_unsigned_prec(1u32, 100)
404    ///     .0
405    ///     .sech_prec_round_ref(20, Floor);
406    /// assert_eq!(c.to_string(), "0.64805412");
407    /// assert_eq!(o, Less);
408    ///
409    /// let (c, o) = Float::from_unsigned_prec(1u32, 100)
410    ///     .0
411    ///     .sech_prec_round_ref(20, Ceiling);
412    /// assert_eq!(c.to_string(), "0.64805508");
413    /// assert_eq!(o, Greater);
414    ///
415    /// let (c, o) = Float::from_unsigned_prec(1u32, 100)
416    ///     .0
417    ///     .sech_prec_round_ref(20, Nearest);
418    /// assert_eq!(c.to_string(), "0.64805412");
419    /// assert_eq!(o, Less);
420    /// ```
421    pub fn sech_prec_round_ref(&self, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
422        assert_ne!(prec, 0);
423        match &self.0 {
424            NaN => (Self::NAN, Equal),
425            // sech(+Inf) = sech(-Inf) = 0+
426            Infinity { .. } => (Self::ZERO, Equal),
427            // sech(+0) = sech(-0) = 1
428            Zero { .. } => (Self::one_prec(prec), Equal),
429            Finite { .. } => sech_prec_round_normal_ref(self, prec, rm),
430        }
431    }
432
433    /// Computes $\operatorname{sech} x$, the hyperbolic secant of a [`Float`], rounding the result
434    /// to the nearest value of the specified precision. The [`Float`] is taken by value. An
435    /// [`Ordering`] is also returned, indicating whether the rounded hyperbolic secant is less
436    /// than, equal to, or greater than the exact hyperbolic secant. Although `NaN`s are not
437    /// comparable to any [`Float`], whenever this function returns a `NaN` it also returns `Equal`.
438    ///
439    /// If the hyperbolic secant is equidistant from two [`Float`]s with the specified precision,
440    /// the [`Float`] with fewer 1s in its binary expansion is chosen. See [`RoundingMode`] for a
441    /// description of the `Nearest` rounding mode.
442    ///
443    /// $$
444    /// f(x,p) = \operatorname{sech} x+\varepsilon.
445    /// $$
446    /// - If $\operatorname{sech} x$ is zero or `NaN`, $\varepsilon$ may be ignored or assumed to be
447    ///   0.
448    /// - If $\operatorname{sech} x$ is nonzero, then $|\varepsilon| < 2^{\lfloor\log_2
449    ///   \operatorname{sech} x\rfloor-p}$.
450    ///
451    /// If the output has a precision, it is `prec`.
452    ///
453    /// Special cases:
454    /// - $f(\text{NaN},p)=\text{NaN}$
455    /// - $f(\infty,p)=0.0$
456    /// - $f(-\infty,p)=0.0$
457    /// - $f(\pm0.0,p)=1.0$
458    ///
459    /// Overflow and underflow:
460    /// - Since $\operatorname{sech} x\leq 1$, the result never overflows.
461    /// - If $0<f(x,p)\leq2^{-2^{30}-1}$, $0.0$ is returned instead.
462    /// - If $2^{-2^{30}-1}<f(x,p)<2^{-2^{30}}$, $2^{-2^{30}}$ is returned instead.
463    ///
464    /// If you want to use a rounding mode other than `Nearest`, consider using
465    /// [`Float::sech_prec_round`] instead. If you know that your target precision is the precision
466    /// of the input, consider using [`Float::sech`] instead.
467    ///
468    /// # Worst-case complexity
469    /// $T(n, m) = O(n^{3/2} \log n \log\log n + m)$
470    ///
471    /// $M(n, m) = O(n \log n + m)$
472    ///
473    /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
474    /// `self.significant_bits()`.
475    ///
476    /// # Panics
477    /// Panics if `prec` is zero.
478    ///
479    /// # Examples
480    /// ```
481    /// use malachite_float::Float;
482    /// use std::cmp::Ordering::*;
483    ///
484    /// let (c, o) = Float::from_unsigned_prec(1u32, 100).0.sech_prec(5);
485    /// assert_eq!(c.to_string(), "0.656");
486    /// assert_eq!(o, Greater);
487    ///
488    /// let (c, o) = Float::from_unsigned_prec(1u32, 100).0.sech_prec(20);
489    /// assert_eq!(c.to_string(), "0.64805412");
490    /// assert_eq!(o, Less);
491    /// ```
492    #[inline]
493    pub fn sech_prec(self, prec: u64) -> (Self, Ordering) {
494        self.sech_prec_round(prec, Nearest)
495    }
496
497    /// Computes $\operatorname{sech} x$, the hyperbolic secant of a [`Float`], rounding the result
498    /// to the nearest value of the specified precision. The [`Float`] is taken by reference. An
499    /// [`Ordering`] is also returned, indicating whether the rounded hyperbolic secant is less
500    /// than, equal to, or greater than the exact hyperbolic secant. Although `NaN`s are not
501    /// comparable to any [`Float`], whenever this function returns a `NaN` it also returns `Equal`.
502    ///
503    /// If the hyperbolic secant is equidistant from two [`Float`]s with the specified precision,
504    /// the [`Float`] with fewer 1s in its binary expansion is chosen. See [`RoundingMode`] for a
505    /// description of the `Nearest` rounding mode.
506    ///
507    /// $$
508    /// f(x,p) = \operatorname{sech} x+\varepsilon.
509    /// $$
510    /// - If $\operatorname{sech} x$ is zero or `NaN`, $\varepsilon$ may be ignored or assumed to be
511    ///   0.
512    /// - If $\operatorname{sech} x$ is nonzero, then $|\varepsilon| < 2^{\lfloor\log_2
513    ///   \operatorname{sech} x\rfloor-p}$.
514    ///
515    /// If the output has a precision, it is `prec`.
516    ///
517    /// Special cases:
518    /// - $f(\text{NaN},p)=\text{NaN}$
519    /// - $f(\infty,p)=0.0$
520    /// - $f(-\infty,p)=0.0$
521    /// - $f(\pm0.0,p)=1.0$
522    ///
523    /// Overflow and underflow:
524    /// - Since $\operatorname{sech} x\leq 1$, the result never overflows.
525    /// - If $0<f(x,p)\leq2^{-2^{30}-1}$, $0.0$ is returned instead.
526    /// - If $2^{-2^{30}-1}<f(x,p)<2^{-2^{30}}$, $2^{-2^{30}}$ is returned instead.
527    ///
528    /// If you want to use a rounding mode other than `Nearest`, consider using
529    /// [`Float::sech_prec_round_ref`] instead. If you know that your target precision is the
530    /// precision of the input, consider using `(&Float).sech()` instead.
531    ///
532    /// # Worst-case complexity
533    /// $T(n, m) = O(n^{3/2} \log n \log\log n + m)$
534    ///
535    /// $M(n, m) = O(n \log n + m)$
536    ///
537    /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
538    /// `self.significant_bits()`.
539    ///
540    /// # Panics
541    /// Panics if `prec` is zero.
542    ///
543    /// # Examples
544    /// ```
545    /// use malachite_float::Float;
546    /// use std::cmp::Ordering::*;
547    ///
548    /// let (c, o) = Float::from_unsigned_prec(1u32, 100).0.sech_prec_ref(5);
549    /// assert_eq!(c.to_string(), "0.656");
550    /// assert_eq!(o, Greater);
551    ///
552    /// let (c, o) = Float::from_unsigned_prec(1u32, 100).0.sech_prec_ref(20);
553    /// assert_eq!(c.to_string(), "0.64805412");
554    /// assert_eq!(o, Less);
555    /// ```
556    #[inline]
557    pub fn sech_prec_ref(&self, prec: u64) -> (Self, Ordering) {
558        self.sech_prec_round_ref(prec, Nearest)
559    }
560
561    /// Computes $\operatorname{sech} x$, the hyperbolic secant of a [`Float`], rounding the result
562    /// with the specified rounding mode. The [`Float`] is taken by value. An [`Ordering`] is also
563    /// returned, indicating whether the rounded hyperbolic secant is less than, equal to, or
564    /// greater than the exact hyperbolic secant. Although `NaN`s are not comparable to any
565    /// [`Float`], whenever this function returns a `NaN` it also returns `Equal`.
566    ///
567    /// The precision of the output is the precision of the input. See [`RoundingMode`] for a
568    /// description of the possible rounding modes.
569    ///
570    /// $$
571    /// f(x,m) = \operatorname{sech} x+\varepsilon.
572    /// $$
573    /// - If $\operatorname{sech} x$ is zero or `NaN`, $\varepsilon$ may be ignored or assumed to be
574    ///   0.
575    /// - If $\operatorname{sech} x$ is nonzero, and $m$ is not `Nearest`, then $|\varepsilon| <
576    ///   2^{\lfloor\log_2 \operatorname{sech} x\rfloor-p+1}$, where $p$ is the precision of the
577    ///   input.
578    /// - If $\operatorname{sech} x$ is nonzero, and $m$ is `Nearest`, then $|\varepsilon| \leq
579    ///   2^{\lfloor\log_2 \operatorname{sech} x\rfloor-p}$, where $p$ is the precision of the
580    ///   input.
581    ///
582    /// If the output has a precision, it is the precision of the input.
583    ///
584    /// Special cases:
585    /// - $f(\text{NaN},m)=\text{NaN}$
586    /// - $f(\infty,m)=0.0$
587    /// - $f(-\infty,m)=0.0$
588    /// - $f(\pm0.0,m)=1.0$
589    ///
590    /// See the [`Float::sech_prec_round`] documentation for information on overflow and underflow.
591    ///
592    /// If you want to specify an output precision, consider using [`Float::sech_prec_round`]
593    /// instead. If you know you'll be using the `Nearest` rounding mode, consider using
594    /// [`Float::sech`] instead.
595    ///
596    /// # Worst-case complexity
597    /// $T(n) = O(n^{3/2} \log n \log\log n)$
598    ///
599    /// $M(n) = O(n \log n)$
600    ///
601    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
602    ///
603    /// # Panics
604    /// Panics if `rm` is `Exact` and `self` is finite and nonzero, since the hyperbolic secant of a
605    /// finite nonzero [`Float`] is never exactly representable.
606    ///
607    /// # Examples
608    /// ```
609    /// use malachite_base::rounding_modes::RoundingMode::*;
610    /// use malachite_float::Float;
611    /// use std::cmp::Ordering::*;
612    ///
613    /// let (c, o) = Float::from_unsigned_prec(1u32, 100).0.sech_round(Floor);
614    /// assert_eq!(c.to_string(), "0.64805427366388539957497735322564");
615    /// assert_eq!(o, Less);
616    ///
617    /// let (c, o) = Float::from_unsigned_prec(1u32, 100).0.sech_round(Ceiling);
618    /// assert_eq!(c.to_string(), "0.64805427366388539957497735322643");
619    /// assert_eq!(o, Greater);
620    ///
621    /// let (c, o) = Float::from_unsigned_prec(1u32, 100).0.sech_round(Nearest);
622    /// assert_eq!(c.to_string(), "0.64805427366388539957497735322643");
623    /// assert_eq!(o, Greater);
624    /// ```
625    #[inline]
626    pub fn sech_round(self, rm: RoundingMode) -> (Self, Ordering) {
627        let prec = self.significant_bits();
628        self.sech_prec_round(prec, rm)
629    }
630
631    /// Computes $\operatorname{sech} x$, the hyperbolic secant of a [`Float`], rounding the result
632    /// with the specified rounding mode. The [`Float`] is taken by reference. An [`Ordering`] is
633    /// also returned, indicating whether the rounded hyperbolic secant is less than, equal to, or
634    /// greater than the exact hyperbolic secant. Although `NaN`s are not comparable to any
635    /// [`Float`], whenever this function returns a `NaN` it also returns `Equal`.
636    ///
637    /// The precision of the output is the precision of the input. See [`RoundingMode`] for a
638    /// description of the possible rounding modes.
639    ///
640    /// $$
641    /// f(x,m) = \operatorname{sech} x+\varepsilon.
642    /// $$
643    /// - If $\operatorname{sech} x$ is zero or `NaN`, $\varepsilon$ may be ignored or assumed to be
644    ///   0.
645    /// - If $\operatorname{sech} x$ is nonzero, and $m$ is not `Nearest`, then $|\varepsilon| <
646    ///   2^{\lfloor\log_2 \operatorname{sech} x\rfloor-p+1}$, where $p$ is the precision of the
647    ///   input.
648    /// - If $\operatorname{sech} x$ is nonzero, and $m$ is `Nearest`, then $|\varepsilon| \leq
649    ///   2^{\lfloor\log_2 \operatorname{sech} x\rfloor-p}$, where $p$ is the precision of the
650    ///   input.
651    ///
652    /// If the output has a precision, it is the precision of the input.
653    ///
654    /// Special cases:
655    /// - $f(\text{NaN},m)=\text{NaN}$
656    /// - $f(\infty,m)=0.0$
657    /// - $f(-\infty,m)=0.0$
658    /// - $f(\pm0.0,m)=1.0$
659    ///
660    /// See the [`Float::sech_prec_round`] documentation for information on overflow and underflow.
661    ///
662    /// If you want to specify an output precision, consider using [`Float::sech_prec_round_ref`]
663    /// instead. If you know you'll be using the `Nearest` rounding mode, consider using
664    /// `(&Float).sech()` instead.
665    ///
666    /// # Worst-case complexity
667    /// $T(n) = O(n^{3/2} \log n \log\log n)$
668    ///
669    /// $M(n) = O(n \log n)$
670    ///
671    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
672    ///
673    /// # Panics
674    /// Panics if `rm` is `Exact` and `self` is finite and nonzero, since the hyperbolic secant of a
675    /// finite nonzero [`Float`] is never exactly representable.
676    ///
677    /// # Examples
678    /// ```
679    /// use malachite_base::rounding_modes::RoundingMode::*;
680    /// use malachite_float::Float;
681    /// use std::cmp::Ordering::*;
682    ///
683    /// let (c, o) = Float::from_unsigned_prec(1u32, 100).0.sech_round_ref(Floor);
684    /// assert_eq!(c.to_string(), "0.64805427366388539957497735322564");
685    /// assert_eq!(o, Less);
686    ///
687    /// let (c, o) = Float::from_unsigned_prec(1u32, 100)
688    ///     .0
689    ///     .sech_round_ref(Ceiling);
690    /// assert_eq!(c.to_string(), "0.64805427366388539957497735322643");
691    /// assert_eq!(o, Greater);
692    ///
693    /// let (c, o) = Float::from_unsigned_prec(1u32, 100)
694    ///     .0
695    ///     .sech_round_ref(Nearest);
696    /// assert_eq!(c.to_string(), "0.64805427366388539957497735322643");
697    /// assert_eq!(o, Greater);
698    /// ```
699    #[inline]
700    pub fn sech_round_ref(&self, rm: RoundingMode) -> (Self, Ordering) {
701        self.sech_prec_round_ref(self.significant_bits(), rm)
702    }
703
704    /// Computes $\operatorname{sech} x$, the hyperbolic secant of a [`Float`], in place, rounding
705    /// the result to the specified precision and with the specified rounding mode. An [`Ordering`]
706    /// is returned, indicating whether the rounded hyperbolic secant is less than, equal to, or
707    /// greater than the exact hyperbolic secant. Although `NaN`s are not comparable to any
708    /// [`Float`], whenever this function sets the [`Float`] to `NaN` it also returns `Equal`.
709    ///
710    /// See [`RoundingMode`] for a description of the possible rounding modes.
711    ///
712    /// $$
713    /// x \gets \operatorname{sech} x+\varepsilon.
714    /// $$
715    /// - If $\operatorname{sech} x$ is zero or `NaN`, $\varepsilon$ may be ignored or assumed to be
716    ///   0.
717    /// - If $\operatorname{sech} x$ is nonzero, and $m$ is not `Nearest`, then $|\varepsilon| <
718    ///   2^{\lfloor\log_2 \operatorname{sech} x\rfloor-p+1}$.
719    /// - If $\operatorname{sech} x$ is nonzero, and $m$ is `Nearest`, then $|\varepsilon| \leq
720    ///   2^{\lfloor\log_2 \operatorname{sech} x\rfloor-p}$.
721    ///
722    /// If the output has a precision, it is `prec`.
723    ///
724    /// See the [`Float::sech_prec_round`] documentation for information on special cases and
725    /// overflow.
726    ///
727    /// If you know you'll be using `Nearest`, consider using [`Float::sech_prec_assign`] instead.
728    /// If you know that your target precision is the precision of the input, consider using
729    /// [`Float::sech_round_assign`] instead. If both of these things are true, consider using
730    /// [`Float::sech_assign`] instead.
731    ///
732    /// # Worst-case complexity
733    /// $T(n, m) = O(n^{3/2} \log n \log\log n + m)$
734    ///
735    /// $M(n, m) = O(n \log n + m)$
736    ///
737    /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
738    /// `self.significant_bits()`.
739    ///
740    /// # Panics
741    /// Panics if `rm` is `Exact` and `self` is finite and nonzero, since the hyperbolic secant of a
742    /// finite nonzero [`Float`] is never exactly representable, or if `prec` is zero.
743    ///
744    /// # Examples
745    /// ```
746    /// use malachite_base::rounding_modes::RoundingMode::*;
747    /// use malachite_float::Float;
748    /// use std::cmp::Ordering::*;
749    ///
750    /// let mut x = Float::from_unsigned_prec(1u32, 100).0;
751    /// assert_eq!(x.sech_prec_round_assign(5, Floor), Less);
752    /// assert_eq!(x.to_string(), "0.625");
753    ///
754    /// let mut x = Float::from_unsigned_prec(1u32, 100).0;
755    /// assert_eq!(x.sech_prec_round_assign(5, Ceiling), Greater);
756    /// assert_eq!(x.to_string(), "0.656");
757    ///
758    /// let mut x = Float::from_unsigned_prec(1u32, 100).0;
759    /// assert_eq!(x.sech_prec_round_assign(5, Nearest), Greater);
760    /// assert_eq!(x.to_string(), "0.656");
761    ///
762    /// let mut x = Float::from_unsigned_prec(1u32, 100).0;
763    /// assert_eq!(x.sech_prec_round_assign(20, Floor), Less);
764    /// assert_eq!(x.to_string(), "0.64805412");
765    ///
766    /// let mut x = Float::from_unsigned_prec(1u32, 100).0;
767    /// assert_eq!(x.sech_prec_round_assign(20, Ceiling), Greater);
768    /// assert_eq!(x.to_string(), "0.64805508");
769    ///
770    /// let mut x = Float::from_unsigned_prec(1u32, 100).0;
771    /// assert_eq!(x.sech_prec_round_assign(20, Nearest), Less);
772    /// assert_eq!(x.to_string(), "0.64805412");
773    /// ```
774    #[inline]
775    pub fn sech_prec_round_assign(&mut self, prec: u64, rm: RoundingMode) -> Ordering {
776        let o;
777        (*self, o) = self.sech_prec_round_ref(prec, rm);
778        o
779    }
780
781    /// Computes $\operatorname{sech} x$, the hyperbolic secant of a [`Float`], in place, rounding
782    /// the result to the nearest value of the specified precision. An [`Ordering`] is returned,
783    /// indicating whether the rounded hyperbolic secant is less than, equal to, or greater than the
784    /// exact hyperbolic secant. Although `NaN`s are not comparable to any [`Float`], whenever this
785    /// function sets the [`Float`] to `NaN` it also returns `Equal`.
786    ///
787    /// If the hyperbolic secant is equidistant from two [`Float`]s with the specified precision,
788    /// the [`Float`] with fewer 1s in its binary expansion is chosen. See [`RoundingMode`] for a
789    /// description of the `Nearest` rounding mode.
790    ///
791    /// $$
792    /// x \gets \operatorname{sech} x+\varepsilon.
793    /// $$
794    /// - If $\operatorname{sech} x$ is zero or `NaN`, $\varepsilon$ may be ignored or assumed to be
795    ///   0.
796    /// - If $\operatorname{sech} x$ is nonzero, then $|\varepsilon| < 2^{\lfloor\log_2
797    ///   \operatorname{sech} x\rfloor-p}$.
798    ///
799    /// If the output has a precision, it is `prec`.
800    ///
801    /// See the [`Float::sech_prec`] documentation for information on special cases, overflow, and
802    /// underflow.
803    ///
804    /// If you want to use a rounding mode other than `Nearest`, consider using
805    /// [`Float::sech_prec_round_assign`] instead. If you know that your target precision is the
806    /// precision of the input, consider using [`Float::sech_assign`] instead.
807    ///
808    /// # Worst-case complexity
809    /// $T(n, m) = O(n^{3/2} \log n \log\log n + m)$
810    ///
811    /// $M(n, m) = O(n \log n + m)$
812    ///
813    /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
814    /// `self.significant_bits()`.
815    ///
816    /// # Panics
817    /// Panics if `prec` is zero.
818    ///
819    /// # Examples
820    /// ```
821    /// use malachite_float::Float;
822    /// use std::cmp::Ordering::*;
823    ///
824    /// let mut x = Float::from_unsigned_prec(1u32, 100).0;
825    /// assert_eq!(x.sech_prec_assign(5), Greater);
826    /// assert_eq!(x.to_string(), "0.656");
827    ///
828    /// let mut x = Float::from_unsigned_prec(1u32, 100).0;
829    /// assert_eq!(x.sech_prec_assign(20), Less);
830    /// assert_eq!(x.to_string(), "0.64805412");
831    /// ```
832    #[inline]
833    pub fn sech_prec_assign(&mut self, prec: u64) -> Ordering {
834        self.sech_prec_round_assign(prec, Nearest)
835    }
836
837    /// Computes $\operatorname{sech} x$, the hyperbolic secant of a [`Float`], in place, rounding
838    /// the result with the specified rounding mode. An [`Ordering`] is returned, indicating whether
839    /// the rounded hyperbolic secant is less than, equal to, or greater than the exact hyperbolic
840    /// secant. Although `NaN`s are not comparable to any [`Float`], whenever this function sets the
841    /// [`Float`] to `NaN` it also returns `Equal`.
842    ///
843    /// The precision of the output is the precision of the input. See [`RoundingMode`] for a
844    /// description of the possible rounding modes.
845    ///
846    /// $$
847    /// x \gets \operatorname{sech} x+\varepsilon.
848    /// $$
849    /// - If $\operatorname{sech} x$ is zero or `NaN`, $\varepsilon$ may be ignored or assumed to be
850    ///   0.
851    /// - If $\operatorname{sech} x$ is nonzero, and $m$ is not `Nearest`, then $|\varepsilon| <
852    ///   2^{\lfloor\log_2 \operatorname{sech} x\rfloor-p+1}$, where $p$ is the precision of the
853    ///   input.
854    /// - If $\operatorname{sech} x$ is nonzero, and $m$ is `Nearest`, then $|\varepsilon| \leq
855    ///   2^{\lfloor\log_2 \operatorname{sech} x\rfloor-p}$, where $p$ is the precision of the
856    ///   input.
857    ///
858    /// If the output has a precision, it is the precision of the input.
859    ///
860    /// See the [`Float::sech_round`] documentation for information on special cases, overflow, and
861    /// underflow.
862    ///
863    /// If you want to specify an output precision, consider using [`Float::sech_prec_round_assign`]
864    /// instead. If you know you'll be using the `Nearest` rounding mode, consider using
865    /// [`Float::sech_assign`] instead.
866    ///
867    /// # Worst-case complexity
868    /// $T(n) = O(n^{3/2} \log n \log\log n)$
869    ///
870    /// $M(n) = O(n \log n)$
871    ///
872    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
873    ///
874    /// # Panics
875    /// Panics if `rm` is `Exact` and `self` is finite and nonzero, since the hyperbolic secant of a
876    /// finite nonzero [`Float`] is never exactly representable.
877    ///
878    /// # Examples
879    /// ```
880    /// use malachite_base::rounding_modes::RoundingMode::*;
881    /// use malachite_float::Float;
882    /// use std::cmp::Ordering::*;
883    ///
884    /// let mut x = Float::from_unsigned_prec(1u32, 100).0;
885    /// assert_eq!(x.sech_round_assign(Floor), Less);
886    /// assert_eq!(x.to_string(), "0.64805427366388539957497735322564");
887    ///
888    /// let mut x = Float::from_unsigned_prec(1u32, 100).0;
889    /// assert_eq!(x.sech_round_assign(Ceiling), Greater);
890    /// assert_eq!(x.to_string(), "0.64805427366388539957497735322643");
891    ///
892    /// let mut x = Float::from_unsigned_prec(1u32, 100).0;
893    /// assert_eq!(x.sech_round_assign(Nearest), Greater);
894    /// assert_eq!(x.to_string(), "0.64805427366388539957497735322643");
895    /// ```
896    #[inline]
897    pub fn sech_round_assign(&mut self, rm: RoundingMode) -> Ordering {
898        let prec = self.significant_bits();
899        self.sech_prec_round_assign(prec, rm)
900    }
901}
902
903impl Float {
904    /// Computes $\operatorname{sech} x$, the hyperbolic secant of a [`Rational`], rounding the
905    /// result to the specified precision and with the specified rounding mode and returning the
906    /// result as a [`Float`]. The [`Rational`] is taken by value. An [`Ordering`] is also returned,
907    /// indicating whether the rounded hyperbolic secant is less than, equal to, or greater than the
908    /// exact hyperbolic secant.
909    ///
910    /// See [`RoundingMode`] for a description of the possible rounding modes.
911    ///
912    /// $$
913    /// f(x,p,m) = \operatorname{sech} x+\varepsilon.
914    /// $$
915    /// - If $m$ is not `Nearest`, then $|\varepsilon| < 2^{\lfloor\log_2 \operatorname{sech}
916    ///   x\rfloor-p+1}$.
917    /// - If $m$ is `Nearest`, then $|\varepsilon| \leq 2^{\lfloor\log_2 \operatorname{sech}
918    ///   x\rfloor-p}$.
919    ///
920    /// These bounds do not apply when the result underflows; see below.
921    ///
922    /// The output has precision `prec`.
923    ///
924    /// Special cases:
925    /// - $f(0,p,m)=1$.
926    ///
927    /// Overflow and underflow:
928    /// - Since $\operatorname{sech} x\leq 1$, the result never overflows.
929    /// - If $0<f(x,p,m)<2^{-2^{30}}$, and $m$ is `Floor` or `Down`, $0.0$ is returned instead.
930    /// - If $0<f(x,p,m)<2^{-2^{30}}$, and $m$ is `Ceiling` or `Up`, $2^{-2^{30}}$ is returned
931    ///   instead.
932    /// - If $0<f(x,p,m)\leq2^{-2^{30}-1}$, and $m$ is `Nearest`, $0.0$ is returned instead.
933    /// - If $2^{-2^{30}-1}<f(x,p,m)<2^{-2^{30}}$, and $m$ is `Nearest`, $2^{-2^{30}}$ is returned
934    ///   instead.
935    ///
936    /// Underflow happens for inputs of magnitude above about $7.4\times10^8$.
937    ///
938    /// If you know you'll be using `Nearest`, consider using [`Float::sech_rational_prec`] instead.
939    ///
940    /// # Worst-case complexity
941    /// $T(n, m) = O(n^{3/2} \log n \log\log n + m (\log m)^2 \log\log m)$
942    ///
943    /// $M(n, m) = O(n \log n + m \log m)$
944    ///
945    /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
946    /// `x.significant_bits()`.
947    ///
948    /// # Panics
949    /// Panics if `prec` is zero, or if `rm` is `Exact` but the result cannot be represented exactly
950    /// with the given precision (which is the case for every nonzero input).
951    ///
952    /// # Examples
953    /// ```
954    /// use malachite_base::rounding_modes::RoundingMode::*;
955    /// use malachite_float::Float;
956    /// use malachite_q::Rational;
957    /// use std::cmp::Ordering::*;
958    ///
959    /// let (c, o) = Float::sech_rational_prec_round(Rational::from_unsigneds(3u8, 5), 5, Floor);
960    /// assert_eq!(c.to_string(), "0.812");
961    /// assert_eq!(o, Less);
962    ///
963    /// let (c, o) = Float::sech_rational_prec_round(Rational::from_unsigneds(3u8, 5), 5, Ceiling);
964    /// assert_eq!(c.to_string(), "0.844");
965    /// assert_eq!(o, Greater);
966    ///
967    /// let (c, o) = Float::sech_rational_prec_round(Rational::from_unsigneds(3u8, 5), 20, Floor);
968    /// assert_eq!(c.to_string(), "0.84355068");
969    /// assert_eq!(o, Less);
970    ///
971    /// let (c, o) = Float::sech_rational_prec_round(Rational::from_unsigneds(3u8, 5), 20, Ceiling);
972    /// assert_eq!(c.to_string(), "0.84355164");
973    /// assert_eq!(o, Greater);
974    /// ```
975    #[allow(clippy::needless_pass_by_value)]
976    #[inline]
977    pub fn sech_rational_prec_round(x: Rational, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
978        Self::sech_rational_prec_round_ref(&x, prec, rm)
979    }
980
981    /// Computes $\operatorname{sech} x$, the hyperbolic secant of a [`Rational`], rounding the
982    /// result to the specified precision and with the specified rounding mode and returning the
983    /// result as a [`Float`]. The [`Rational`] is taken by reference. An [`Ordering`] is also
984    /// returned, indicating whether the rounded hyperbolic secant is less than, equal to, or
985    /// greater than the exact hyperbolic secant.
986    ///
987    /// See [`RoundingMode`] for a description of the possible rounding modes.
988    ///
989    /// $$
990    /// f(x,p,m) = \operatorname{sech} x+\varepsilon.
991    /// $$
992    /// - If $m$ is not `Nearest`, then $|\varepsilon| < 2^{\lfloor\log_2 \operatorname{sech}
993    ///   x\rfloor-p+1}$.
994    /// - If $m$ is `Nearest`, then $|\varepsilon| \leq 2^{\lfloor\log_2 \operatorname{sech}
995    ///   x\rfloor-p}$.
996    ///
997    /// These bounds do not apply when the result underflows; see below.
998    ///
999    /// The output has precision `prec`.
1000    ///
1001    /// Special cases:
1002    /// - $f(0,p,m)=1$.
1003    ///
1004    /// Overflow and underflow:
1005    /// - Since $\operatorname{sech} x\leq 1$, the result never overflows.
1006    /// - If $0<f(x,p,m)<2^{-2^{30}}$, and $m$ is `Floor` or `Down`, $0.0$ is returned instead.
1007    /// - If $0<f(x,p,m)<2^{-2^{30}}$, and $m$ is `Ceiling` or `Up`, $2^{-2^{30}}$ is returned
1008    ///   instead.
1009    /// - If $0<f(x,p,m)\leq2^{-2^{30}-1}$, and $m$ is `Nearest`, $0.0$ is returned instead.
1010    /// - If $2^{-2^{30}-1}<f(x,p,m)<2^{-2^{30}}$, and $m$ is `Nearest`, $2^{-2^{30}}$ is returned
1011    ///   instead.
1012    ///
1013    /// Underflow happens for inputs of magnitude above about $7.4\times10^8$.
1014    ///
1015    /// If you know you'll be using `Nearest`, consider using [`Float::sech_rational_prec_ref`]
1016    /// instead.
1017    ///
1018    /// # Worst-case complexity
1019    /// $T(n, m) = O(n^{3/2} \log n \log\log n + m (\log m)^2 \log\log m)$
1020    ///
1021    /// $M(n, m) = O(n \log n + m \log m)$
1022    ///
1023    /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
1024    /// `x.significant_bits()`.
1025    ///
1026    /// # Panics
1027    /// Panics if `prec` is zero, or if `rm` is `Exact` but the result cannot be represented exactly
1028    /// with the given precision (which is the case for every nonzero input).
1029    ///
1030    /// # Examples
1031    /// ```
1032    /// use malachite_base::rounding_modes::RoundingMode::*;
1033    /// use malachite_float::Float;
1034    /// use malachite_q::Rational;
1035    /// use std::cmp::Ordering::*;
1036    ///
1037    /// let (c, o) =
1038    ///     Float::sech_rational_prec_round_ref(&Rational::from_unsigneds(3u8, 5), 5, Floor);
1039    /// assert_eq!(c.to_string(), "0.812");
1040    /// assert_eq!(o, Less);
1041    ///
1042    /// let (c, o) =
1043    ///     Float::sech_rational_prec_round_ref(&Rational::from_unsigneds(3u8, 5), 5, Ceiling);
1044    /// assert_eq!(c.to_string(), "0.844");
1045    /// assert_eq!(o, Greater);
1046    ///
1047    /// let (c, o) =
1048    ///     Float::sech_rational_prec_round_ref(&Rational::from_unsigneds(3u8, 5), 20, Floor);
1049    /// assert_eq!(c.to_string(), "0.84355068");
1050    /// assert_eq!(o, Less);
1051    ///
1052    /// let (c, o) =
1053    ///     Float::sech_rational_prec_round_ref(&Rational::from_unsigneds(3u8, 5), 20, Ceiling);
1054    /// assert_eq!(c.to_string(), "0.84355164");
1055    /// assert_eq!(o, Greater);
1056    /// ```
1057    pub fn sech_rational_prec_round_ref(
1058        x: &Rational,
1059        prec: u64,
1060        rm: RoundingMode,
1061    ) -> (Self, Ordering) {
1062        assert_ne!(prec, 0);
1063        if *x == 0u32 {
1064            // sech(0) = 1, exactly
1065            return (Self::one_prec(prec), Equal);
1066        }
1067        sech_rational_helper(x, prec, rm)
1068    }
1069
1070    /// Computes $\operatorname{sech} x$, the hyperbolic secant of a [`Rational`], rounding the
1071    /// result to the nearest value of the specified precision and returning the result as a
1072    /// [`Float`]. The [`Rational`] is taken by value. An [`Ordering`] is also returned, indicating
1073    /// whether the rounded hyperbolic secant is less than, equal to, or greater than the exact
1074    /// hyperbolic secant.
1075    ///
1076    /// If the hyperbolic secant is equidistant from two [`Float`]s with the specified precision,
1077    /// the [`Float`] with fewer 1s in its binary expansion is chosen. See [`RoundingMode`] for a
1078    /// description of the `Nearest` rounding mode.
1079    ///
1080    /// $$
1081    /// f(x,p) = \operatorname{sech} x+\varepsilon,
1082    /// $$
1083    /// where $|\varepsilon| \leq 2^{\lfloor\log_2 \operatorname{sech} x\rfloor-p}$ (unless the
1084    /// result underflows; see below).
1085    ///
1086    /// The output has precision `prec`.
1087    ///
1088    /// Special cases:
1089    /// - $f(0,p)=1$.
1090    ///
1091    /// Overflow and underflow:
1092    /// - Since $\operatorname{sech} x\leq 1$, the result never overflows.
1093    /// - If $0<f(x,p)\leq2^{-2^{30}-1}$, $0.0$ is returned instead.
1094    /// - If $2^{-2^{30}-1}<f(x,p)<2^{-2^{30}}$, $2^{-2^{30}}$ is returned instead.
1095    ///
1096    /// If you want to use a rounding mode other than `Nearest`, consider using
1097    /// [`Float::sech_rational_prec_round`] instead.
1098    ///
1099    /// # Worst-case complexity
1100    /// $T(n, m) = O(n^{3/2} \log n \log\log n + m (\log m)^2 \log\log m)$
1101    ///
1102    /// $M(n, m) = O(n \log n + m \log m)$
1103    ///
1104    /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
1105    /// `x.significant_bits()`.
1106    ///
1107    /// # Panics
1108    /// Panics if `prec` is zero.
1109    ///
1110    /// # Examples
1111    /// ```
1112    /// use malachite_base::num::basic::traits::Zero;
1113    /// use malachite_float::Float;
1114    /// use malachite_q::Rational;
1115    /// use std::cmp::Ordering::*;
1116    ///
1117    /// let (c, o) = Float::sech_rational_prec(Rational::from_unsigneds(3u8, 5), 5);
1118    /// assert_eq!(c.to_string(), "0.844");
1119    /// assert_eq!(o, Greater);
1120    ///
1121    /// let (c, o) = Float::sech_rational_prec(Rational::from_unsigneds(3u8, 5), 20);
1122    /// assert_eq!(c.to_string(), "0.84355068");
1123    /// assert_eq!(o, Less);
1124    ///
1125    /// let (c, o) = Float::sech_rational_prec(Rational::ZERO, 10);
1126    /// assert_eq!(c.to_string(), "1.0000");
1127    /// assert_eq!(o, Equal);
1128    /// ```
1129    #[allow(clippy::needless_pass_by_value)]
1130    #[inline]
1131    pub fn sech_rational_prec(x: Rational, prec: u64) -> (Self, Ordering) {
1132        Self::sech_rational_prec_round_ref(&x, prec, Nearest)
1133    }
1134
1135    /// Computes $\operatorname{sech} x$, the hyperbolic secant of a [`Rational`], rounding the
1136    /// result to the nearest value of the specified precision and returning the result as a
1137    /// [`Float`]. The [`Rational`] is taken by reference. An [`Ordering`] is also returned,
1138    /// indicating whether the rounded hyperbolic secant is less than, equal to, or greater than the
1139    /// exact hyperbolic cosine.
1140    ///
1141    /// If the hyperbolic secant is equidistant from two [`Float`]s with the specified precision,
1142    /// the [`Float`] with fewer 1s in its binary expansion is chosen. See [`RoundingMode`] for a
1143    /// description of the `Nearest` rounding mode.
1144    ///
1145    /// $$
1146    /// f(x,p) = \operatorname{sech} x+\varepsilon,
1147    /// $$
1148    /// where $|\varepsilon| \leq 2^{\lfloor\log_2 \operatorname{sech} x\rfloor-p}$ (unless the
1149    /// result underflows; see below).
1150    ///
1151    /// The output has precision `prec`.
1152    ///
1153    /// Special cases:
1154    /// - $f(0,p)=1$.
1155    ///
1156    /// Overflow and underflow:
1157    /// - Since $\operatorname{sech} x\leq 1$, the result never overflows.
1158    /// - If $0<f(x,p)\leq2^{-2^{30}-1}$, $0.0$ is returned instead.
1159    /// - If $2^{-2^{30}-1}<f(x,p)<2^{-2^{30}}$, $2^{-2^{30}}$ is returned instead.
1160    ///
1161    /// If you want to use a rounding mode other than `Nearest`, consider using
1162    /// [`Float::sech_rational_prec_round_ref`] instead.
1163    ///
1164    /// # Worst-case complexity
1165    /// $T(n, m) = O(n^{3/2} \log n \log\log n + m (\log m)^2 \log\log m)$
1166    ///
1167    /// $M(n, m) = O(n \log n + m \log m)$
1168    ///
1169    /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
1170    /// `x.significant_bits()`.
1171    ///
1172    /// # Panics
1173    /// Panics if `prec` is zero.
1174    ///
1175    /// # Examples
1176    /// ```
1177    /// use malachite_base::num::basic::traits::Zero;
1178    /// use malachite_float::Float;
1179    /// use malachite_q::Rational;
1180    /// use std::cmp::Ordering::*;
1181    ///
1182    /// let (c, o) = Float::sech_rational_prec_ref(&Rational::from_unsigneds(3u8, 5), 5);
1183    /// assert_eq!(c.to_string(), "0.844");
1184    /// assert_eq!(o, Greater);
1185    ///
1186    /// let (c, o) = Float::sech_rational_prec_ref(&Rational::from_unsigneds(3u8, 5), 20);
1187    /// assert_eq!(c.to_string(), "0.84355068");
1188    /// assert_eq!(o, Less);
1189    ///
1190    /// let (c, o) = Float::sech_rational_prec_ref(&Rational::ZERO, 10);
1191    /// assert_eq!(c.to_string(), "1.0000");
1192    /// assert_eq!(o, Equal);
1193    /// ```
1194    #[inline]
1195    pub fn sech_rational_prec_ref(x: &Rational, prec: u64) -> (Self, Ordering) {
1196        Self::sech_rational_prec_round_ref(x, prec, Nearest)
1197    }
1198}
1199
1200impl Sech for Float {
1201    type Output = Self;
1202
1203    /// Computes $\operatorname{sech} x$, the hyperbolic secant of a [`Float`], taking it by value.
1204    ///
1205    /// If the output has a precision, it is the precision of the input. If the hyperbolic secant is
1206    /// equidistant from two [`Float`]s with the specified precision, the [`Float`] with fewer 1s in
1207    /// its binary expansion is chosen. See [`RoundingMode`] for a description of the `Nearest`
1208    /// rounding mode.
1209    ///
1210    /// $$
1211    /// f(x) = \operatorname{sech} x+\varepsilon.
1212    /// $$
1213    /// - If $\operatorname{sech} x$ is zero or `NaN`, $\varepsilon$ may be ignored or assumed to be
1214    ///   0.
1215    /// - If $\operatorname{sech} x$ is nonzero, then $|\varepsilon| < 2^{\lfloor\log_2
1216    ///   \operatorname{sech} x\rfloor-p}$, where $p$ is the precision of the input.
1217    ///
1218    /// Special cases:
1219    /// - $f(\text{NaN})=\text{NaN}$
1220    /// - $f(\infty)=0.0$
1221    /// - $f(-\infty)=0.0$
1222    /// - $f(\pm0.0)=1.0$
1223    ///
1224    /// See the [`Float::sech_round`] documentation for information on overflow and underflow.
1225    ///
1226    /// If you want to use a rounding mode other than `Nearest`, consider using
1227    /// [`Float::sech_round`] instead. If you want to specify the output precision, consider using
1228    /// [`Float::sech_prec`]. If you want both of these things, consider using
1229    /// [`Float::sech_prec_round`].
1230    ///
1231    /// # Worst-case complexity
1232    /// $T(n) = O(n^{3/2} \log n \log\log n)$
1233    ///
1234    /// $M(n) = O(n \log n)$
1235    ///
1236    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
1237    ///
1238    /// # Examples
1239    /// ```
1240    /// use malachite_base::num::arithmetic::traits::Sech;
1241    /// use malachite_base::num::basic::traits::{Infinity, NaN, NegativeInfinity};
1242    /// use malachite_float::Float;
1243    ///
1244    /// assert!(Float::NAN.sech().is_nan());
1245    /// assert_eq!(Float::INFINITY.sech(), 0);
1246    /// assert_eq!(Float::NEGATIVE_INFINITY.sech(), 0);
1247    /// assert_eq!(
1248    ///     Float::from_unsigned_prec(1u32, 100).0.sech().to_string(),
1249    ///     "0.64805427366388539957497735322643"
1250    /// );
1251    /// ```
1252    #[inline]
1253    fn sech(self) -> Self {
1254        let prec = self.significant_bits();
1255        self.sech_prec_round(prec, Nearest).0
1256    }
1257}
1258
1259impl Sech for &Float {
1260    type Output = Float;
1261
1262    /// Computes $\operatorname{sech} x$, the hyperbolic secant of a [`Float`], taking it by
1263    /// reference.
1264    ///
1265    /// If the output has a precision, it is the precision of the input. If the hyperbolic secant is
1266    /// equidistant from two [`Float`]s with the specified precision, the [`Float`] with fewer 1s in
1267    /// its binary expansion is chosen. See [`RoundingMode`] for a description of the `Nearest`
1268    /// rounding mode.
1269    ///
1270    /// $$
1271    /// f(x) = \operatorname{sech} x+\varepsilon.
1272    /// $$
1273    /// - If $\operatorname{sech} x$ is zero or `NaN`, $\varepsilon$ may be ignored or assumed to be
1274    ///   0.
1275    /// - If $\operatorname{sech} x$ is nonzero, then $|\varepsilon| < 2^{\lfloor\log_2
1276    ///   \operatorname{sech} x\rfloor-p}$, where $p$ is the precision of the input.
1277    ///
1278    /// Special cases:
1279    /// - $f(\text{NaN})=\text{NaN}$
1280    /// - $f(\infty)=0.0$
1281    /// - $f(-\infty)=0.0$
1282    /// - $f(\pm0.0)=1.0$
1283    ///
1284    /// See the [`Float::sech_round`] documentation for information on overflow and underflow.
1285    ///
1286    /// If you want to use a rounding mode other than `Nearest`, consider using
1287    /// [`Float::sech_round_ref`] instead. If you want to specify the output precision, consider
1288    /// using [`Float::sech_prec_ref`]. If you want both of these things, consider using
1289    /// [`Float::sech_prec_round_ref`].
1290    ///
1291    /// # Worst-case complexity
1292    /// $T(n) = O(n^{3/2} \log n \log\log n)$
1293    ///
1294    /// $M(n) = O(n \log n)$
1295    ///
1296    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
1297    ///
1298    /// # Examples
1299    /// ```
1300    /// use malachite_base::num::arithmetic::traits::Sech;
1301    /// use malachite_base::num::basic::traits::{Infinity, NaN, NegativeInfinity};
1302    /// use malachite_float::Float;
1303    ///
1304    /// assert!((&Float::NAN).sech().is_nan());
1305    /// assert_eq!((&Float::INFINITY).sech(), 0);
1306    /// assert_eq!((&Float::NEGATIVE_INFINITY).sech(), 0);
1307    /// assert_eq!(
1308    ///     (&Float::from_unsigned_prec(1u32, 100).0).sech().to_string(),
1309    ///     "0.64805427366388539957497735322643"
1310    /// );
1311    /// ```
1312    #[inline]
1313    fn sech(self) -> Float {
1314        self.sech_prec_round_ref(self.significant_bits(), Nearest).0
1315    }
1316}
1317
1318impl SechAssign for Float {
1319    /// Computes $\operatorname{sech} x$, the hyperbolic secant of a [`Float`], in place.
1320    ///
1321    /// If the output has a precision, it is the precision of the input. If the hyperbolic secant is
1322    /// equidistant from two [`Float`]s with the specified precision, the [`Float`] with fewer 1s in
1323    /// its binary expansion is chosen. See [`RoundingMode`] for a description of the `Nearest`
1324    /// rounding mode.
1325    ///
1326    /// $$
1327    /// x \gets \operatorname{sech} x+\varepsilon.
1328    /// $$
1329    /// - If $\operatorname{sech} x$ is zero or `NaN`, $\varepsilon$ may be ignored or assumed to be
1330    ///   0.
1331    /// - If $\operatorname{sech} x$ is nonzero, then $|\varepsilon| < 2^{\lfloor\log_2
1332    ///   \operatorname{sech} x\rfloor-p}$, where $p$ is the precision of the input.
1333    ///
1334    /// See the [`Float::sech`] documentation for information on special cases, overflow, and
1335    /// underflow.
1336    ///
1337    /// If you want to use a rounding mode other than `Nearest`, consider using
1338    /// [`Float::sech_round_assign`] instead. If you want to specify the output precision, consider
1339    /// using [`Float::sech_prec_assign`]. If you want both of these things, consider using
1340    /// [`Float::sech_prec_round_assign`].
1341    ///
1342    /// # Worst-case complexity
1343    /// $T(n) = O(n^{3/2} \log n \log\log n)$
1344    ///
1345    /// $M(n) = O(n \log n)$
1346    ///
1347    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
1348    ///
1349    /// # Examples
1350    /// ```
1351    /// use malachite_base::num::arithmetic::traits::SechAssign;
1352    /// use malachite_base::num::basic::traits::{Infinity, NaN, NegativeInfinity};
1353    /// use malachite_float::Float;
1354    ///
1355    /// let mut x = Float::NAN;
1356    /// x.sech_assign();
1357    /// assert!(x.is_nan());
1358    ///
1359    /// let mut x = Float::INFINITY;
1360    /// x.sech_assign();
1361    /// assert_eq!(x, 0);
1362    ///
1363    /// let mut x = Float::NEGATIVE_INFINITY;
1364    /// x.sech_assign();
1365    /// assert_eq!(x, 0);
1366    ///
1367    /// let mut x = Float::from_unsigned_prec(1u32, 100).0;
1368    /// x.sech_assign();
1369    /// assert_eq!(x.to_string(), "0.64805427366388539957497735322643");
1370    /// ```
1371    #[inline]
1372    fn sech_assign(&mut self) {
1373        let prec = self.significant_bits();
1374        self.sech_prec_round_assign(prec, Nearest);
1375    }
1376}
1377
1378/// Computes $\operatorname{sech} x$, the hyperbolic secant of a primitive float. The result is
1379/// correctly rounded.
1380///
1381/// $$
1382/// f(x) = \operatorname{sech} x+\varepsilon.
1383/// $$
1384/// - If $\operatorname{sech} x$ is zero or `NaN`, $\varepsilon$ may be ignored or assumed to be 0.
1385/// - If $\operatorname{sech} x$ is nonzero, then $|\varepsilon| < 2^{\lfloor\log_2
1386///   \operatorname{sech} x\rfloor-p}$, where $p$ is the precision of the output (typically 24 if
1387///   `T` is a [`f32`] and 53 if `T` is a [`f64`], but less if the output is subnormal).
1388///
1389/// Special cases:
1390/// - $f(\text{NaN})=\text{NaN}$
1391/// - $f(\pm\infty)=0.0$
1392/// - $f(\pm0.0)=1.0$
1393///
1394/// Overflow is not possible, since the result lies in $[0, 1]$. An `x` of large magnitude gives a
1395/// subnormal result, or underflows to `0.0`.
1396///
1397/// # Worst-case complexity
1398/// Constant time and additional memory.
1399///
1400/// # Examples
1401/// ```
1402/// use malachite_base::num::float::NiceFloat;
1403/// use malachite_float::float::arithmetic::sech::primitive_float_sech;
1404///
1405/// assert!(primitive_float_sech(f32::NAN).is_nan());
1406/// assert_eq!(
1407///     NiceFloat(primitive_float_sech(f32::INFINITY)),
1408///     NiceFloat(0.0)
1409/// );
1410/// assert_eq!(NiceFloat(primitive_float_sech(-0.0f32)), NiceFloat(1.0));
1411/// assert_eq!(
1412///     NiceFloat(primitive_float_sech(1.0f32)),
1413///     NiceFloat(0.6480543)
1414/// );
1415/// assert_eq!(
1416///     NiceFloat(primitive_float_sech(-1.0f64)),
1417///     NiceFloat(0.6480542736638853)
1418/// );
1419/// assert_eq!(
1420///     NiceFloat(primitive_float_sech(720.0f64)),
1421///     NiceFloat(4.06446160484e-313)
1422/// );
1423/// assert_eq!(NiceFloat(primitive_float_sech(746.0f64)), NiceFloat(0.0));
1424/// ```
1425#[inline]
1426#[allow(clippy::type_repetition_in_bounds)]
1427pub fn primitive_float_sech<T: PrimitiveFloat>(x: T) -> T
1428where
1429    Float: From<T> + PartialOrd<T>,
1430    for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
1431{
1432    emulate_float_to_float_fn(Float::sech_prec, x)
1433}
1434
1435/// Computes $\operatorname{sech} x$, the hyperbolic secant of a [`Rational`], returning the result
1436/// as a primitive float. The result is correctly rounded.
1437///
1438/// $$
1439/// f(x) = \operatorname{sech} x+\varepsilon.
1440/// $$
1441/// - If $\operatorname{sech} x$ is zero, $\varepsilon$ may be ignored or assumed to be 0.
1442/// - If $\operatorname{sech} x$ is nonzero, then $|\varepsilon| < 2^{\lfloor\log_2
1443///   \operatorname{sech} x\rfloor-p}$, where $p$ is the precision of the output (typically 24 if
1444///   `T` is a [`f32`] and 53 if `T` is a [`f64`], but less if the output is subnormal).
1445///
1446/// Special cases:
1447/// - $f(0)=1$
1448///
1449/// Overflow is not possible, since the result lies in $(0, 1]$. An `x` of large magnitude gives a
1450/// subnormal result, or underflows to `0.0`.
1451///
1452/// # Worst-case complexity
1453/// $T(m) = O(m (\log m)^2 \log\log m)$
1454///
1455/// $M(m) = O(m \log m)$
1456///
1457/// where $T$ is time, $M$ is additional memory, and $m$ is `x.significant_bits()`.
1458///
1459/// # Examples
1460/// ```
1461/// use malachite_base::num::basic::traits::Zero;
1462/// use malachite_base::num::float::NiceFloat;
1463/// use malachite_float::float::arithmetic::sech::primitive_float_sech_rational;
1464/// use malachite_q::Rational;
1465///
1466/// assert_eq!(
1467///     NiceFloat(primitive_float_sech_rational::<f64>(&Rational::ZERO)),
1468///     NiceFloat(1.0)
1469/// );
1470/// assert_eq!(
1471///     NiceFloat(primitive_float_sech_rational::<f64>(
1472///         &Rational::from_unsigneds(1u8, 3)
1473///     )),
1474///     NiceFloat(0.9469052537634979)
1475/// );
1476/// assert_eq!(
1477///     NiceFloat(primitive_float_sech_rational::<f64>(
1478///         &Rational::from_signeds(-1i8, 3)
1479///     )),
1480///     NiceFloat(0.9469052537634979)
1481/// );
1482/// assert_eq!(
1483///     NiceFloat(primitive_float_sech_rational::<f64>(&Rational::from(10000))),
1484///     NiceFloat(0.0)
1485/// );
1486/// ```
1487#[inline]
1488#[allow(clippy::type_repetition_in_bounds)]
1489pub fn primitive_float_sech_rational<T: PrimitiveFloat>(x: &Rational) -> T
1490where
1491    Float: PartialOrd<T>,
1492    for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
1493{
1494    emulate_rational_to_float_fn(Float::sech_rational_prec_ref, x)
1495}