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}