malachite_float/float/arithmetic/asech.rs
1// Copyright © 2026 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::InnerFloat::{Finite, Infinity, NaN, Zero};
10use crate::float::arithmetic::asinh::round_with_error;
11use crate::{Float, emulate_float_to_float_fn, emulate_rational_to_float_fn};
12use core::cmp::Ordering::{self, *};
13use malachite_base::fail_on_untested_path;
14use malachite_base::num::arithmetic::traits::{
15 Asech, AsechAssign, CeilingLogBase2, Ln, Ln1PlusX, Reciprocal, Sign, Sqrt,
16};
17use malachite_base::num::basic::floats::PrimitiveFloat;
18use malachite_base::num::basic::integers::PrimitiveInt;
19use malachite_base::num::basic::traits::{
20 Infinity as InfinityTrait, NaN as NaNTrait, One, Zero as ZeroTrait,
21};
22use malachite_base::num::conversion::traits::{ExactFrom, RoundingFrom};
23use malachite_base::num::logic::traits::SignificantBits;
24use malachite_base::rounding_modes::RoundingMode::{self, *};
25use malachite_nz::platform::Limb;
26use malachite_q::Rational;
27
28// Computes asech(x) = acosh(1/x) = ln((1 + sqrt(1 - x^2))/x) for a `Float` x with 0 < x < 1. MPFR
29// has no asech, so this is Malachite's own algorithm. Computing 1/x first would be ill-conditioned
30// near x = 1, where acosh has an infinite derivative, and would overflow for the smallest `Float`s,
31// so the two halves of the domain are handled differently, each without cancellation:
32//
33// - For 1/2 <= x < 1, let t = 1 - x, which is exact (Sterbenz). Then 1 - x^2 = t(1 + x), and
34// asech(x) = ln(1 + u) with u = (t + sqrt(t(1 + x)))/x, all of whose terms are positive. Each of
35// the five operations forming u has a relative error of at most 2^-wp, so u's is below 4 * 2^-wp
36// (the square root halves the error of its argument). Since ln(1+u) >= u/(1+u), that moves
37// ln(1+u) by less than 4.02 * 2^-wp ln(1+u), about 4 ulps, and its own rounding adds 1/2 ulp:
38// under 2^3 ulps.
39// - For 0 < x < 1/2, asech(x) = ln(1 + s) - ln(x) with s = sqrt((1 - x)(1 + x)) in (0.86, 1]. Both
40// terms are positive, ln(1 + s) < 0.7 < -ln(x), and the sum exceeds 1.3, so its ulp is at least
41// 2^(1-wp). s has relative error below 2.5 * 2^-wp, which moves ln(1 + s) by less than 1.3 *
42// 2^-wp; with the three roundings (of ln(1 + s), of ln(x), and of the sum), each at most half an
43// ulp of the sum, the error is below 3 ulps: under 2^3 ulps again.
44//
45// If t(1 + x) underflows, which needs an x with a precision above 2^30, sqrt(t) sqrt(1 + x) is used
46// instead; its relative error is below 2^-wp more, which the bound absorbs.
47fn asech_prec_round_normal_ref(x: &Float, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
48 assert_ne!(rm, Exact, "Inexact asech");
49 let near_one = x.get_exponent().unwrap() == 0; // 1/2 <= x < 1
50 // t = 1 - x, exact at x's precision for 1/2 <= x < 1
51 let t = near_one.then(|| {
52 let (t, o) = Float::ONE.sub_prec_ref_ref(x, x.get_prec().unwrap());
53 assert_eq!(o, Equal);
54 t
55 });
56 let exp_x = i64::from(x.get_exponent().unwrap());
57 let mut working_prec = prec + prec.ceiling_log_base_2() + 10;
58 let mut increment = Limb::WIDTH;
59 loop {
60 let t = if let Some(t) = &t {
61 // 1 + x
62 let one_plus_x = x.add_prec_ref_val(Float::ONE, working_prec).0;
63 let s = if t.get_exponent().unwrap() > const { Float::MIN_EXPONENT + 1 } {
64 // sqrt(t(1 + x))
65 t.mul_prec_ref_val(one_plus_x, working_prec).0.sqrt()
66 } else {
67 fail_on_untested_path("asech_prec_round_normal_ref, t(1 + x) may underflow");
68 t.sqrt_prec_ref(working_prec).0 * one_plus_x.sqrt()
69 };
70 // ln(1 + (t + s)/x)
71 s.add_prec_val_ref(t, working_prec)
72 .0
73 .div_prec_val_ref(x, working_prec)
74 .0
75 .ln_1_plus_x()
76 } else if exp_x << 1 <= 1 - i64::exact_from(working_prec) {
77 // x^2 < 2^(1-wp), so ln(1 + sqrt(1 - x^2)) = ln 2 - c with 0 < c < x^2, which is at
78 // most 1 ulp of the sum (whose ulp is at least 2^(1-wp)): with the three roundings the
79 // error stays below 2.5 ulps, under 2^3 ulps
80 Float::ln_2_prec(working_prec).0 - x.ln_prec_ref(working_prec).0
81 } else {
82 // s = sqrt((1 - x)(1 + x))
83 let s = (Float::ONE.sub_prec_val_ref(x, working_prec).0
84 * x.add_prec_ref_val(Float::ONE, working_prec).0)
85 .sqrt();
86 // ln(1 + s) - ln(x)
87 (s + Float::ONE).ln() - x.ln_prec_ref(working_prec).0
88 };
89 if let Some(result) = round_with_error(t, working_prec, 3, prec, rm) {
90 return result;
91 }
92 working_prec += increment;
93 increment = working_prec >> 1;
94 }
95}
96
97impl Float {
98 /// Computes $\operatorname{asech} x$, the inverse hyperbolic secant of a [`Float`], rounding
99 /// the result to the specified precision and with the specified rounding mode. The [`Float`] is
100 /// taken by value. An [`Ordering`] is also returned, indicating whether the rounded inverse
101 /// hyperbolic secant is less than, equal to, or greater than the exact inverse hyperbolic
102 /// secant. Although `NaN`s are not comparable to any [`Float`], whenever this function returns
103 /// a `NaN` it also returns `Equal`.
104 ///
105 /// See [`RoundingMode`] for a description of the possible rounding modes.
106 ///
107 /// $$
108 /// f(x,p,m) = \operatorname{asech} x+\varepsilon.
109 /// $$
110 /// - If $\operatorname{asech} x$ is infinite, zero, or NaN, $\varepsilon$ may be ignored or
111 /// assumed to be 0.
112 /// - If $\operatorname{asech} x$ is finite and nonzero, and $m$ is not `Nearest`, then
113 /// $|\varepsilon| < 2^{\lfloor\log_2 \operatorname{asech} x\rfloor-p+1}$.
114 /// - If $\operatorname{asech} x$ is finite and nonzero, and $m$ is `Nearest`, then
115 /// $|\varepsilon| \leq 2^{\lfloor\log_2 \operatorname{asech} x\rfloor-p}$.
116 ///
117 /// If the output has a precision, it is `prec`.
118 ///
119 /// Special cases:
120 /// - $f(\text{NaN},p,m)=\text{NaN}$
121 /// - $f(\pm\infty,p,m)=\text{NaN}$
122 /// - $f(\pm0.0,p,m)=\infty$
123 /// - $f(1,p,m)=0.0$
124 /// - $f(x,p,m)=\text{NaN}$ if $x<0$ or $x>1$
125 ///
126 /// The result never overflows, since $\operatorname{asech} x < \ln(2/x) < 2^{30}$ for every
127 /// positive [`Float`] $x$. It underflows only for an $x$ within $2^{-2^{31}}$ of 1, since
128 /// $\operatorname{asech}(1-t) > \sqrt t$, and such an $x$ needs a precision above $2^{31}$.
129 ///
130 /// If you know you'll be using `Nearest`, consider using [`Float::asech_prec`] instead. If you
131 /// know that your target precision is the precision of the input, consider using
132 /// [`Float::asech_round`] instead. If both of these things are true, consider using
133 /// [`Float::asech`] instead.
134 ///
135 /// # Worst-case complexity
136 /// $T(n) = O(n (\log n)^2 \log\log n)$
137 ///
138 /// $M(n) = O(n \log n)$
139 ///
140 /// where $T$ is time, $M$ is additional memory, and $n$ is `max(prec,
141 /// self.significant_bits())`.
142 ///
143 /// # Panics
144 /// Panics if `rm` is `Exact` and `self` is finite, nonzero, and less than 1 in absolute value,
145 /// since the inverse hyperbolic secant of such a [`Float`] is never exactly representable, or
146 /// if `prec` is zero.
147 ///
148 /// # Examples
149 /// ```
150 /// use malachite_base::rounding_modes::RoundingMode::*;
151 /// use malachite_float::Float;
152 /// use std::cmp::Ordering::*;
153 ///
154 /// let (c, o) = (Float::one_prec(100) >> 1u32).asech_prec_round(5, Floor);
155 /// assert_eq!(c.to_string(), "1.31");
156 /// assert_eq!(o, Less);
157 ///
158 /// let (c, o) = (Float::one_prec(100) >> 1u32).asech_prec_round(5, Ceiling);
159 /// assert_eq!(c.to_string(), "1.38");
160 /// assert_eq!(o, Greater);
161 ///
162 /// let (c, o) = (Float::one_prec(100) >> 1u32).asech_prec_round(5, Nearest);
163 /// assert_eq!(c.to_string(), "1.31");
164 /// assert_eq!(o, Less);
165 ///
166 /// let (c, o) = (Float::one_prec(100) >> 1u32).asech_prec_round(20, Floor);
167 /// assert_eq!(c.to_string(), "1.3169575");
168 /// assert_eq!(o, Less);
169 ///
170 /// let (c, o) = (Float::one_prec(100) >> 1u32).asech_prec_round(20, Ceiling);
171 /// assert_eq!(c.to_string(), "1.3169594");
172 /// assert_eq!(o, Greater);
173 ///
174 /// let (c, o) = (Float::one_prec(100) >> 1u32).asech_prec_round(20, Nearest);
175 /// assert_eq!(c.to_string(), "1.3169575");
176 /// assert_eq!(o, Less);
177 /// ```
178 #[inline]
179 pub fn asech_prec_round(self, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
180 self.asech_prec_round_ref(prec, rm)
181 }
182
183 /// Computes $\operatorname{asech} x$, the inverse hyperbolic secant of a [`Float`], rounding
184 /// the result to the specified precision and with the specified rounding mode. The [`Float`] is
185 /// taken by reference. An [`Ordering`] is also returned, indicating whether the rounded inverse
186 /// hyperbolic secant is less than, equal to, or greater than the exact inverse hyperbolic
187 /// secant. Although `NaN`s are not comparable to any [`Float`], whenever this function returns
188 /// a `NaN` it also returns `Equal`.
189 ///
190 /// See [`RoundingMode`] for a description of the possible rounding modes.
191 ///
192 /// $$
193 /// f(x,p,m) = \operatorname{asech} x+\varepsilon.
194 /// $$
195 /// - If $\operatorname{asech} x$ is infinite, zero, or NaN, $\varepsilon$ may be ignored or
196 /// assumed to be 0.
197 /// - If $\operatorname{asech} x$ is finite and nonzero, and $m$ is not `Nearest`, then
198 /// $|\varepsilon| < 2^{\lfloor\log_2 \operatorname{asech} x\rfloor-p+1}$.
199 /// - If $\operatorname{asech} x$ is finite and nonzero, and $m$ is `Nearest`, then
200 /// $|\varepsilon| \leq 2^{\lfloor\log_2 \operatorname{asech} x\rfloor-p}$.
201 ///
202 /// If the output has a precision, it is `prec`.
203 ///
204 /// Special cases:
205 /// - $f(\text{NaN},p,m)=\text{NaN}$
206 /// - $f(\pm\infty,p,m)=\text{NaN}$
207 /// - $f(\pm0.0,p,m)=\infty$
208 /// - $f(1,p,m)=0.0$
209 /// - $f(x,p,m)=\text{NaN}$ if $x<0$ or $x>1$
210 ///
211 /// The result never overflows, since $\operatorname{asech} x < \ln(2/x) < 2^{30}$ for every
212 /// positive [`Float`] $x$. It underflows only for an $x$ within $2^{-2^{31}}$ of 1, since
213 /// $\operatorname{asech}(1-t) > \sqrt t$, and such an $x$ needs a precision above $2^{31}$.
214 ///
215 /// If you know you'll be using `Nearest`, consider using [`Float::asech_prec_ref`] instead. If
216 /// you know that your target precision is the precision of the input, consider using
217 /// [`Float::asech_round_ref`] instead. If both of these things are true, consider using
218 /// `(&Float).asech()` instead.
219 ///
220 /// # Worst-case complexity
221 /// $T(n) = O(n (\log n)^2 \log\log n)$
222 ///
223 /// $M(n) = O(n \log n)$
224 ///
225 /// where $T$ is time, $M$ is additional memory, and $n$ is `max(prec,
226 /// self.significant_bits())`.
227 ///
228 /// # Panics
229 /// Panics if `rm` is `Exact` and `self` is finite, nonzero, and less than 1 in absolute value,
230 /// since the inverse hyperbolic secant of such a [`Float`] is never exactly representable, or
231 /// if `prec` is zero.
232 ///
233 /// # Examples
234 /// ```
235 /// use malachite_base::rounding_modes::RoundingMode::*;
236 /// use malachite_float::Float;
237 /// use std::cmp::Ordering::*;
238 ///
239 /// let (c, o) = (Float::one_prec(100) >> 1u32).asech_prec_round_ref(5, Floor);
240 /// assert_eq!(c.to_string(), "1.31");
241 /// assert_eq!(o, Less);
242 ///
243 /// let (c, o) = (Float::one_prec(100) >> 1u32).asech_prec_round_ref(5, Ceiling);
244 /// assert_eq!(c.to_string(), "1.38");
245 /// assert_eq!(o, Greater);
246 ///
247 /// let (c, o) = (Float::one_prec(100) >> 1u32).asech_prec_round_ref(5, Nearest);
248 /// assert_eq!(c.to_string(), "1.31");
249 /// assert_eq!(o, Less);
250 ///
251 /// let (c, o) = (Float::one_prec(100) >> 1u32).asech_prec_round_ref(20, Floor);
252 /// assert_eq!(c.to_string(), "1.3169575");
253 /// assert_eq!(o, Less);
254 ///
255 /// let (c, o) = (Float::one_prec(100) >> 1u32).asech_prec_round_ref(20, Ceiling);
256 /// assert_eq!(c.to_string(), "1.3169594");
257 /// assert_eq!(o, Greater);
258 ///
259 /// let (c, o) = (Float::one_prec(100) >> 1u32).asech_prec_round_ref(20, Nearest);
260 /// assert_eq!(c.to_string(), "1.3169575");
261 /// assert_eq!(o, Less);
262 /// ```
263 pub fn asech_prec_round_ref(&self, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
264 assert_ne!(prec, 0);
265 match &self.0 {
266 // asech is NaN for NaN, both infinities, and everything below 0
267 NaN | Infinity { .. } | Finite { sign: false, .. } => (Self::NAN, Equal),
268 // asech(+/-0) = +Inf, the limit from above; like ln, asech treats -0 as 0
269 Zero { .. } => (Self::INFINITY, Equal),
270 Finite { .. } => match self.partial_cmp(&1u32).unwrap() {
271 Less => asech_prec_round_normal_ref(self, prec, rm),
272 // asech(1) = +0
273 Equal => (Self::ZERO, Equal),
274 // asech is NaN above 1
275 Greater => (Self::NAN, Equal),
276 },
277 }
278 }
279
280 /// Computes $\operatorname{asech} x$, the inverse hyperbolic secant of a [`Float`], rounding
281 /// the result to the nearest value of the specified precision. The [`Float`] is taken by value.
282 /// An [`Ordering`] is also returned, indicating whether the rounded inverse hyperbolic secant
283 /// is less than, equal to, or greater than the exact inverse hyperbolic secant. Although `NaN`s
284 /// are not comparable to any [`Float`], whenever this function returns a `NaN` it also returns
285 /// `Equal`.
286 ///
287 /// If the inverse hyperbolic secant is equidistant from two [`Float`]s with the specified
288 /// precision, the [`Float`] with fewer 1s in its binary expansion is chosen. See
289 /// [`RoundingMode`] for a description of the `Nearest` rounding mode.
290 ///
291 /// $$
292 /// f(x,p) = \operatorname{asech} x+\varepsilon.
293 /// $$
294 /// - If $\operatorname{asech} x$ is infinite, zero, or NaN, $\varepsilon$ may be ignored or
295 /// assumed to be 0.
296 /// - If $\operatorname{asech} x$ is finite and nonzero, then $|\varepsilon| < 2^{\lfloor\log_2
297 /// \operatorname{asech} x\rfloor-p}$.
298 ///
299 /// If the output has a precision, it is `prec`.
300 ///
301 /// Special cases:
302 /// - $f(\text{NaN},p)=\text{NaN}$
303 /// - $f(\pm\infty,p)=\text{NaN}$
304 /// - $f(\pm0.0,p)=\infty$
305 /// - $f(1,p)=0.0$
306 /// - $f(x,p)=\text{NaN}$ if $x<0$ or $x>1$
307 ///
308 /// The result never overflows, since $\operatorname{asech} x < \ln(2/x) < 2^{30}$ for every
309 /// positive [`Float`] $x$. It underflows only for an $x$ within $2^{-2^{31}}$ of 1, since
310 /// $\operatorname{asech}(1-t) > \sqrt t$, and such an $x$ needs a precision above $2^{31}$.
311 ///
312 /// If you want to use a rounding mode other than `Nearest`, consider using
313 /// [`Float::asech_prec_round`] instead. If you know that your target precision is the precision
314 /// of the input, consider using [`Float::asech`] instead.
315 ///
316 /// # Worst-case complexity
317 /// $T(n) = O(n (\log n)^2 \log\log n)$
318 ///
319 /// $M(n) = O(n \log n)$
320 ///
321 /// where $T$ is time, $M$ is additional memory, and $n$ is `max(prec,
322 /// self.significant_bits())`.
323 ///
324 /// # Panics
325 /// Panics if `prec` is zero.
326 ///
327 /// # Examples
328 /// ```
329 /// use malachite_float::Float;
330 /// use std::cmp::Ordering::*;
331 ///
332 /// let (c, o) = (Float::one_prec(100) >> 1u32).asech_prec(5);
333 /// assert_eq!(c.to_string(), "1.31");
334 /// assert_eq!(o, Less);
335 ///
336 /// let (c, o) = (Float::one_prec(100) >> 1u32).asech_prec(20);
337 /// assert_eq!(c.to_string(), "1.3169575");
338 /// assert_eq!(o, Less);
339 /// ```
340 #[inline]
341 pub fn asech_prec(self, prec: u64) -> (Self, Ordering) {
342 self.asech_prec_round(prec, Nearest)
343 }
344
345 /// Computes $\operatorname{asech} x$, the inverse hyperbolic secant of a [`Float`], rounding
346 /// the result to the nearest value of the specified precision. The [`Float`] is taken by
347 /// reference. An [`Ordering`] is also returned, indicating whether the rounded inverse
348 /// hyperbolic secant is less than, equal to, or greater than the exact inverse hyperbolic
349 /// secant. Although `NaN`s are not comparable to any [`Float`], whenever this function returns
350 /// a `NaN` it also returns `Equal`.
351 ///
352 /// If the inverse hyperbolic secant is equidistant from two [`Float`]s with the specified
353 /// precision, the [`Float`] with fewer 1s in its binary expansion is chosen. See
354 /// [`RoundingMode`] for a description of the `Nearest` rounding mode.
355 ///
356 /// $$
357 /// f(x,p) = \operatorname{asech} x+\varepsilon.
358 /// $$
359 /// - If $\operatorname{asech} x$ is infinite, zero, or NaN, $\varepsilon$ may be ignored or
360 /// assumed to be 0.
361 /// - If $\operatorname{asech} x$ is finite and nonzero, then $|\varepsilon| < 2^{\lfloor\log_2
362 /// \operatorname{asech} x\rfloor-p}$.
363 ///
364 /// If the output has a precision, it is `prec`.
365 ///
366 /// Special cases:
367 /// - $f(\text{NaN},p)=\text{NaN}$
368 /// - $f(\pm\infty,p)=\text{NaN}$
369 /// - $f(\pm0.0,p)=\infty$
370 /// - $f(1,p)=0.0$
371 /// - $f(x,p)=\text{NaN}$ if $x<0$ or $x>1$
372 ///
373 /// The result never overflows, since $\operatorname{asech} x < \ln(2/x) < 2^{30}$ for every
374 /// positive [`Float`] $x$. It underflows only for an $x$ within $2^{-2^{31}}$ of 1, since
375 /// $\operatorname{asech}(1-t) > \sqrt t$, and such an $x$ needs a precision above $2^{31}$.
376 ///
377 /// If you want to use a rounding mode other than `Nearest`, consider using
378 /// [`Float::asech_prec_round_ref`] instead. If you know that your target precision is the
379 /// precision of the input, consider using `(&Float).asech()` instead.
380 ///
381 /// # Worst-case complexity
382 /// $T(n) = O(n (\log n)^2 \log\log n)$
383 ///
384 /// $M(n) = O(n \log n)$
385 ///
386 /// where $T$ is time, $M$ is additional memory, and $n$ is `max(prec,
387 /// self.significant_bits())`.
388 ///
389 /// # Panics
390 /// Panics if `prec` is zero.
391 ///
392 /// # Examples
393 /// ```
394 /// use malachite_float::Float;
395 /// use std::cmp::Ordering::*;
396 ///
397 /// let (c, o) = (Float::one_prec(100) >> 1u32).asech_prec_ref(5);
398 /// assert_eq!(c.to_string(), "1.31");
399 /// assert_eq!(o, Less);
400 ///
401 /// let (c, o) = (Float::one_prec(100) >> 1u32).asech_prec_ref(20);
402 /// assert_eq!(c.to_string(), "1.3169575");
403 /// assert_eq!(o, Less);
404 /// ```
405 #[inline]
406 pub fn asech_prec_ref(&self, prec: u64) -> (Self, Ordering) {
407 self.asech_prec_round_ref(prec, Nearest)
408 }
409
410 /// Computes $\operatorname{asech} x$, the inverse hyperbolic secant of a [`Float`], rounding
411 /// the result with the specified rounding mode. The [`Float`] is taken by value. An
412 /// [`Ordering`] is also returned, indicating whether the rounded inverse hyperbolic secant is
413 /// less than, equal to, or greater than the exact inverse hyperbolic secant. Although `NaN`s
414 /// are not comparable to any [`Float`], whenever this function returns a `NaN` it also returns
415 /// `Equal`.
416 ///
417 /// The precision of the output is the precision of the input. See [`RoundingMode`] for a
418 /// description of the possible rounding modes.
419 ///
420 /// $$
421 /// f(x,m) = \operatorname{asech} x+\varepsilon.
422 /// $$
423 /// - If $\operatorname{asech} x$ is infinite, zero, or NaN, $\varepsilon$ may be ignored or
424 /// assumed to be 0.
425 /// - If $\operatorname{asech} x$ is finite and nonzero, and $m$ is not `Nearest`, then
426 /// $|\varepsilon| < 2^{\lfloor\log_2 \operatorname{asech} x\rfloor-p+1}$, where $p$ is the
427 /// precision of the input.
428 /// - If $\operatorname{asech} x$ is finite and nonzero, and $m$ is `Nearest`, then
429 /// $|\varepsilon| \leq 2^{\lfloor\log_2 \operatorname{asech} x\rfloor-p}$, where $p$ is the
430 /// precision of the input.
431 ///
432 /// If the output has a precision, it is the precision of the input.
433 ///
434 /// Special cases:
435 /// - $f(\text{NaN},m)=\text{NaN}$
436 /// - $f(\pm\infty,m)=\text{NaN}$
437 /// - $f(\pm0.0,m)=\infty$
438 /// - $f(1,m)=0.0$
439 /// - $f(x,m)=\text{NaN}$ if $x<0$ or $x>1$
440 ///
441 /// The result never overflows, since $\operatorname{asech} x < \ln(2/x) < 2^{30}$ for every
442 /// positive [`Float`] $x$. It underflows only for an $x$ within $2^{-2^{31}}$ of 1, since
443 /// $\operatorname{asech}(1-t) > \sqrt t$, and such an $x$ needs a precision above $2^{31}$.
444 ///
445 /// If you want to specify an output precision, consider using [`Float::asech_prec_round`]
446 /// instead. If you know you'll be using the `Nearest` rounding mode, consider using
447 /// [`Float::asech`] instead.
448 ///
449 /// # Worst-case complexity
450 /// $T(n) = O(n (\log n)^2 \log\log n)$
451 ///
452 /// $M(n) = O(n \log n)$
453 ///
454 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
455 ///
456 /// # Panics
457 /// Panics if `rm` is `Exact` and `self` is finite, nonzero, and less than 1 in absolute value,
458 /// since the inverse hyperbolic secant of such a [`Float`] is never exactly representable.
459 ///
460 /// # Examples
461 /// ```
462 /// use malachite_base::rounding_modes::RoundingMode::*;
463 /// use malachite_float::Float;
464 /// use std::cmp::Ordering::*;
465 ///
466 /// let (c, o) = (Float::one_prec(100) >> 1u32).asech_round(Floor);
467 /// assert_eq!(c.to_string(), "1.3169578969248167086250463473073");
468 /// assert_eq!(o, Less);
469 ///
470 /// let (c, o) = (Float::one_prec(100) >> 1u32).asech_round(Ceiling);
471 /// assert_eq!(c.to_string(), "1.3169578969248167086250463473089");
472 /// assert_eq!(o, Greater);
473 ///
474 /// let (c, o) = (Float::one_prec(100) >> 1u32).asech_round(Nearest);
475 /// assert_eq!(c.to_string(), "1.3169578969248167086250463473073");
476 /// assert_eq!(o, Less);
477 /// ```
478 #[inline]
479 pub fn asech_round(self, rm: RoundingMode) -> (Self, Ordering) {
480 let prec = self.significant_bits();
481 self.asech_prec_round(prec, rm)
482 }
483
484 /// Computes $\operatorname{asech} x$, the inverse hyperbolic secant of a [`Float`], rounding
485 /// the result with the specified rounding mode. The [`Float`] is taken by reference. An
486 /// [`Ordering`] is also returned, indicating whether the rounded inverse hyperbolic secant is
487 /// less than, equal to, or greater than the exact inverse hyperbolic secant. Although `NaN`s
488 /// are not comparable to any [`Float`], whenever this function returns a `NaN` it also returns
489 /// `Equal`.
490 ///
491 /// The precision of the output is the precision of the input. See [`RoundingMode`] for a
492 /// description of the possible rounding modes.
493 ///
494 /// $$
495 /// f(x,m) = \operatorname{asech} x+\varepsilon.
496 /// $$
497 /// - If $\operatorname{asech} x$ is infinite, zero, or NaN, $\varepsilon$ may be ignored or
498 /// assumed to be 0.
499 /// - If $\operatorname{asech} x$ is finite and nonzero, and $m$ is not `Nearest`, then
500 /// $|\varepsilon| < 2^{\lfloor\log_2 \operatorname{asech} x\rfloor-p+1}$, where $p$ is the
501 /// precision of the input.
502 /// - If $\operatorname{asech} x$ is finite and nonzero, and $m$ is `Nearest`, then
503 /// $|\varepsilon| \leq 2^{\lfloor\log_2 \operatorname{asech} x\rfloor-p}$, where $p$ is the
504 /// precision of the input.
505 ///
506 /// If the output has a precision, it is the precision of the input.
507 ///
508 /// Special cases:
509 /// - $f(\text{NaN},m)=\text{NaN}$
510 /// - $f(\pm\infty,m)=\text{NaN}$
511 /// - $f(\pm0.0,m)=\infty$
512 /// - $f(1,m)=0.0$
513 /// - $f(x,m)=\text{NaN}$ if $x<0$ or $x>1$
514 ///
515 /// The result never overflows, since $\operatorname{asech} x < \ln(2/x) < 2^{30}$ for every
516 /// positive [`Float`] $x$. It underflows only for an $x$ within $2^{-2^{31}}$ of 1, since
517 /// $\operatorname{asech}(1-t) > \sqrt t$, and such an $x$ needs a precision above $2^{31}$.
518 ///
519 /// If you want to specify an output precision, consider using [`Float::asech_prec_round_ref`]
520 /// instead. If you know you'll be using the `Nearest` rounding mode, consider using
521 /// `(&Float).asech()` instead.
522 ///
523 /// # Worst-case complexity
524 /// $T(n) = O(n (\log n)^2 \log\log n)$
525 ///
526 /// $M(n) = O(n \log n)$
527 ///
528 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
529 ///
530 /// # Panics
531 /// Panics if `rm` is `Exact` and `self` is finite, nonzero, and less than 1 in absolute value,
532 /// since the inverse hyperbolic secant of such a [`Float`] is never exactly representable.
533 ///
534 /// # Examples
535 /// ```
536 /// use malachite_base::rounding_modes::RoundingMode::*;
537 /// use malachite_float::Float;
538 /// use std::cmp::Ordering::*;
539 ///
540 /// let (c, o) = (Float::one_prec(100) >> 1u32).asech_round_ref(Floor);
541 /// assert_eq!(c.to_string(), "1.3169578969248167086250463473073");
542 /// assert_eq!(o, Less);
543 ///
544 /// let (c, o) = (Float::one_prec(100) >> 1u32).asech_round_ref(Ceiling);
545 /// assert_eq!(c.to_string(), "1.3169578969248167086250463473089");
546 /// assert_eq!(o, Greater);
547 ///
548 /// let (c, o) = (Float::one_prec(100) >> 1u32).asech_round_ref(Nearest);
549 /// assert_eq!(c.to_string(), "1.3169578969248167086250463473073");
550 /// assert_eq!(o, Less);
551 /// ```
552 #[inline]
553 pub fn asech_round_ref(&self, rm: RoundingMode) -> (Self, Ordering) {
554 self.asech_prec_round_ref(self.significant_bits(), rm)
555 }
556
557 /// Computes $\operatorname{asech} x$, the inverse hyperbolic secant of a [`Float`], rounding
558 /// the result to the specified precision and with the specified rounding mode. The [`Float`] is
559 /// replaced by the result, and an [`Ordering`] is returned, indicating whether the rounded
560 /// inverse hyperbolic secant is less than, equal to, or greater than the exact inverse
561 /// hyperbolic secant. Although `NaN`s are not comparable to any [`Float`], whenever this
562 /// function sets a `NaN` it also returns `Equal`.
563 ///
564 /// See [`RoundingMode`] for a description of the possible rounding modes.
565 ///
566 /// $$
567 /// x \gets \operatorname{asech} x+\varepsilon.
568 /// $$
569 /// - If $\operatorname{asech} x$ is infinite, zero, or NaN, $\varepsilon$ may be ignored or
570 /// assumed to be 0.
571 /// - If $\operatorname{asech} x$ is finite and nonzero, and $m$ is not `Nearest`, then
572 /// $|\varepsilon| < 2^{\lfloor\log_2 \operatorname{asech} x\rfloor-p+1}$.
573 /// - If $\operatorname{asech} x$ is finite and nonzero, and $m$ is `Nearest`, then
574 /// $|\varepsilon| \leq 2^{\lfloor\log_2 \operatorname{asech} x\rfloor-p}$.
575 ///
576 /// If the output has a precision, it is `prec`.
577 ///
578 /// See the [`Float::asech_prec_round`] documentation for information on special cases,
579 /// overflow, and underflow.
580 ///
581 /// If you know you'll be using `Nearest`, consider using [`Float::asech_prec_assign`] instead.
582 /// If you know that your target precision is the precision of the input, consider using
583 /// [`Float::asech_round_assign`] instead. If both of these things are true, consider using
584 /// [`Float::asech_assign`] instead.
585 ///
586 /// # Worst-case complexity
587 /// $T(n) = O(n (\log n)^2 \log\log n)$
588 ///
589 /// $M(n) = O(n \log n)$
590 ///
591 /// where $T$ is time, $M$ is additional memory, and $n$ is `max(prec,
592 /// self.significant_bits())`.
593 ///
594 /// # Panics
595 /// Panics if `rm` is `Exact` and `self` is finite, nonzero, and less than 1 in absolute value,
596 /// since the inverse hyperbolic secant of such a [`Float`] is never exactly representable, or
597 /// if `prec` is zero.
598 ///
599 /// # Examples
600 /// ```
601 /// use malachite_base::rounding_modes::RoundingMode::*;
602 /// use malachite_float::Float;
603 /// use std::cmp::Ordering::*;
604 ///
605 /// let mut x = Float::one_prec(100) >> 1u32;
606 /// assert_eq!(x.asech_prec_round_assign(5, Floor), Less);
607 /// assert_eq!(x.to_string(), "1.31");
608 ///
609 /// let mut x = Float::one_prec(100) >> 1u32;
610 /// assert_eq!(x.asech_prec_round_assign(5, Ceiling), Greater);
611 /// assert_eq!(x.to_string(), "1.38");
612 ///
613 /// let mut x = Float::one_prec(100) >> 1u32;
614 /// assert_eq!(x.asech_prec_round_assign(5, Nearest), Less);
615 /// assert_eq!(x.to_string(), "1.31");
616 ///
617 /// let mut x = Float::one_prec(100) >> 1u32;
618 /// assert_eq!(x.asech_prec_round_assign(20, Floor), Less);
619 /// assert_eq!(x.to_string(), "1.3169575");
620 ///
621 /// let mut x = Float::one_prec(100) >> 1u32;
622 /// assert_eq!(x.asech_prec_round_assign(20, Ceiling), Greater);
623 /// assert_eq!(x.to_string(), "1.3169594");
624 ///
625 /// let mut x = Float::one_prec(100) >> 1u32;
626 /// assert_eq!(x.asech_prec_round_assign(20, Nearest), Less);
627 /// assert_eq!(x.to_string(), "1.3169575");
628 /// ```
629 #[inline]
630 pub fn asech_prec_round_assign(&mut self, prec: u64, rm: RoundingMode) -> Ordering {
631 let o;
632 (*self, o) = self.asech_prec_round_ref(prec, rm);
633 o
634 }
635
636 /// Computes $\operatorname{asech} x$, the inverse hyperbolic secant of a [`Float`], rounding
637 /// the result to the nearest value of the specified precision. The [`Float`] is replaced by the
638 /// result, and an [`Ordering`] is returned, indicating whether the rounded inverse hyperbolic
639 /// secant is less than, equal to, or greater than the exact inverse hyperbolic secant. Although
640 /// `NaN`s are not comparable to any [`Float`], whenever this function sets a `NaN` it also
641 /// returns `Equal`.
642 ///
643 /// If the inverse hyperbolic secant is equidistant from two [`Float`]s with the specified
644 /// precision, the [`Float`] with fewer 1s in its binary expansion is chosen. See
645 /// [`RoundingMode`] for a description of the `Nearest` rounding mode.
646 ///
647 /// $$
648 /// x \gets \operatorname{asech} x+\varepsilon.
649 /// $$
650 /// - If $\operatorname{asech} x$ is infinite, zero, or NaN, $\varepsilon$ may be ignored or
651 /// assumed to be 0.
652 /// - If $\operatorname{asech} x$ is finite and nonzero, then $|\varepsilon| < 2^{\lfloor\log_2
653 /// \operatorname{asech} x\rfloor-p}$.
654 ///
655 /// If the output has a precision, it is `prec`.
656 ///
657 /// See the [`Float::asech_prec`] documentation for information on special cases, overflow, and
658 /// underflow.
659 ///
660 /// If you want to use a rounding mode other than `Nearest`, consider using
661 /// [`Float::asech_prec_round_assign`] instead. If you know that your target precision is the
662 /// precision of the input, consider using [`Float::asech_assign`] instead.
663 ///
664 /// # Worst-case complexity
665 /// $T(n) = O(n (\log n)^2 \log\log n)$
666 ///
667 /// $M(n) = O(n \log n)$
668 ///
669 /// where $T$ is time, $M$ is additional memory, and $n$ is `max(prec,
670 /// self.significant_bits())`.
671 ///
672 /// # Panics
673 /// Panics if `prec` is zero.
674 ///
675 /// # Examples
676 /// ```
677 /// use malachite_float::Float;
678 /// use std::cmp::Ordering::*;
679 ///
680 /// let mut x = Float::one_prec(100) >> 1u32;
681 /// assert_eq!(x.asech_prec_assign(5), Less);
682 /// assert_eq!(x.to_string(), "1.31");
683 ///
684 /// let mut x = Float::one_prec(100) >> 1u32;
685 /// assert_eq!(x.asech_prec_assign(20), Less);
686 /// assert_eq!(x.to_string(), "1.3169575");
687 /// ```
688 #[inline]
689 pub fn asech_prec_assign(&mut self, prec: u64) -> Ordering {
690 self.asech_prec_round_assign(prec, Nearest)
691 }
692
693 /// Computes $\operatorname{asech} x$, the inverse hyperbolic secant of a [`Float`], rounding
694 /// the result with the specified rounding mode. The [`Float`] is replaced by the result, and an
695 /// [`Ordering`] is returned, indicating whether the rounded inverse hyperbolic secant is less
696 /// than, equal to, or greater than the exact inverse hyperbolic secant. Although `NaN`s are not
697 /// comparable to any [`Float`], whenever this function sets a `NaN` it also returns `Equal`.
698 ///
699 /// The precision of the output is the precision of the input. See [`RoundingMode`] for a
700 /// description of the possible rounding modes.
701 ///
702 /// $$
703 /// x \gets \operatorname{asech} x+\varepsilon.
704 /// $$
705 /// - If $\operatorname{asech} x$ is infinite, zero, or NaN, $\varepsilon$ may be ignored or
706 /// assumed to be 0.
707 /// - If $\operatorname{asech} x$ is finite and nonzero, and $m$ is not `Nearest`, then
708 /// $|\varepsilon| < 2^{\lfloor\log_2 \operatorname{asech} x\rfloor-p+1}$, where $p$ is the
709 /// precision of the input.
710 /// - If $\operatorname{asech} x$ is finite and nonzero, and $m$ is `Nearest`, then
711 /// $|\varepsilon| \leq 2^{\lfloor\log_2 \operatorname{asech} x\rfloor-p}$, where $p$ is the
712 /// precision of the input.
713 ///
714 /// If the output has a precision, it is the precision of the input.
715 ///
716 /// See the [`Float::asech_round`] documentation for information on special cases, overflow, and
717 /// underflow.
718 ///
719 /// If you want to specify an output precision, consider using
720 /// [`Float::asech_prec_round_assign`] instead. If you know you'll be using the `Nearest`
721 /// rounding mode, consider using [`Float::asech_assign`] instead.
722 ///
723 /// # Worst-case complexity
724 /// $T(n) = O(n (\log n)^2 \log\log n)$
725 ///
726 /// $M(n) = O(n \log n)$
727 ///
728 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
729 ///
730 /// # Panics
731 /// Panics if `rm` is `Exact` and `self` is finite, nonzero, and less than 1 in absolute value,
732 /// since the inverse hyperbolic secant of such a [`Float`] is never exactly representable.
733 ///
734 /// # Examples
735 /// ```
736 /// use malachite_base::rounding_modes::RoundingMode::*;
737 /// use malachite_float::Float;
738 /// use std::cmp::Ordering::*;
739 ///
740 /// let mut x = Float::one_prec(100) >> 1u32;
741 /// assert_eq!(x.asech_round_assign(Floor), Less);
742 /// assert_eq!(x.to_string(), "1.3169578969248167086250463473073");
743 ///
744 /// let mut x = Float::one_prec(100) >> 1u32;
745 /// assert_eq!(x.asech_round_assign(Ceiling), Greater);
746 /// assert_eq!(x.to_string(), "1.3169578969248167086250463473089");
747 ///
748 /// let mut x = Float::one_prec(100) >> 1u32;
749 /// assert_eq!(x.asech_round_assign(Nearest), Less);
750 /// assert_eq!(x.to_string(), "1.3169578969248167086250463473073");
751 /// ```
752 #[inline]
753 pub fn asech_round_assign(&mut self, rm: RoundingMode) -> Ordering {
754 let prec = self.significant_bits();
755 self.asech_prec_round_assign(prec, rm)
756 }
757
758 /// Computes $\operatorname{asech} x$, the inverse hyperbolic secant of a [`Rational`], rounding
759 /// the result to the specified precision and with the specified rounding mode and returning the
760 /// result as a [`Float`]. The [`Rational`] is taken by value. An [`Ordering`] is also returned,
761 /// indicating whether the rounded inverse hyperbolic secant is less than, equal to, or greater
762 /// than the exact inverse hyperbolic secant. Although `NaN`s are not comparable to any
763 /// [`Float`], whenever this function returns a `NaN` it also returns `Equal`.
764 ///
765 /// See [`RoundingMode`] for a description of the possible rounding modes.
766 ///
767 /// $$
768 /// f(x,p,m) = \operatorname{asech} x+\varepsilon.
769 /// $$
770 /// - If $\operatorname{asech} x$ is infinite, zero, or NaN, $\varepsilon$ may be ignored or
771 /// assumed to be 0.
772 /// - If $\operatorname{asech} x$ is finite and nonzero, and $m$ is not `Nearest`, then
773 /// $|\varepsilon| < 2^{\lfloor\log_2 \operatorname{asech} x\rfloor-p+1}$.
774 /// - If $\operatorname{asech} x$ is finite and nonzero, and $m$ is `Nearest`, then
775 /// $|\varepsilon| \leq 2^{\lfloor\log_2 \operatorname{asech} x\rfloor-p}$.
776 ///
777 /// These bounds do not apply when the result underflows; see below.
778 ///
779 /// If the output has a precision, it is `prec`.
780 ///
781 /// Special cases:
782 /// - $f(0,p,m)=\infty$
783 /// - $f(1,p,m)=0.0$
784 /// - $f(x,p,m)=\text{NaN}$ if $x<0$ or $x>1$
785 ///
786 /// Overflow and underflow:
787 /// - The result never overflows: for $0<x<1$ with denominator $d$, $\operatorname{asech} x <
788 /// \ln(2/x) \leq \ln 2d$.
789 /// - If $0<f(x,p,m)<2^{-2^{30}}$, and $m$ is `Floor` or `Down`, $0.0$ is returned instead.
790 /// - If $0<f(x,p,m)<2^{-2^{30}}$, and $m$ is `Ceiling` or `Up`, $2^{-2^{30}}$ is returned
791 /// instead.
792 /// - If $0<f(x,p,m)\leq2^{-2^{30}-1}$, and $m$ is `Nearest`, $0.0$ is returned instead.
793 /// - If $2^{-2^{30}-1}<f(x,p,m)<2^{-2^{30}}$, and $m$ is `Nearest`, $2^{-2^{30}}$ is returned
794 /// instead.
795 ///
796 /// Underflow requires an $x$ within $2^{-2^{31}}$ of 1, since $\operatorname{asech}(1-t) >
797 /// \sqrt t$, and so a denominator of more than $2^{31}$ bits.
798 ///
799 /// If you know you'll be using `Nearest`, consider using [`Float::asech_rational_prec`]
800 /// instead.
801 ///
802 /// # Worst-case complexity
803 /// $T(n, m) = O(n (\log n)^2 \log\log n + m (\log m)^2 \log\log m)$
804 ///
805 /// $M(n, m) = O(n \log n + m \log m)$
806 ///
807 /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
808 /// `x.significant_bits()`: the logarithm is computed at a working precision of about $n$, and
809 /// the input is handled with `Rational` arithmetic.
810 ///
811 /// # Panics
812 /// Panics if `prec` is zero, or if `rm` is `Exact` but the result cannot be represented exactly
813 /// with the given precision (which is the case for every $x$ with $0<x<1$).
814 ///
815 /// # Examples
816 /// ```
817 /// use malachite_base::rounding_modes::RoundingMode::*;
818 /// use malachite_float::Float;
819 /// use malachite_q::Rational;
820 /// use std::cmp::Ordering::*;
821 ///
822 /// let (c, o) = Float::asech_rational_prec_round(Rational::from_unsigneds(1u8, 3), 5, Floor);
823 /// assert_eq!(c.to_string(), "1.75");
824 /// assert_eq!(o, Less);
825 ///
826 /// let (c, o) = Float::asech_rational_prec_round(Rational::from_unsigneds(1u8, 3), 5, Ceiling);
827 /// assert_eq!(c.to_string(), "1.81");
828 /// assert_eq!(o, Greater);
829 ///
830 /// let (c, o) = Float::asech_rational_prec_round(Rational::from_unsigneds(1u8, 3), 20, Floor);
831 /// assert_eq!(c.to_string(), "1.7627468");
832 /// assert_eq!(o, Less);
833 ///
834 /// let (c, o) =
835 /// Float::asech_rational_prec_round(Rational::from_unsigneds(1u8, 3), 20, Ceiling);
836 /// assert_eq!(c.to_string(), "1.7627487");
837 /// assert_eq!(o, Greater);
838 /// ```
839 #[inline]
840 #[allow(clippy::needless_pass_by_value)]
841 pub fn asech_rational_prec_round(x: Rational, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
842 Self::asech_rational_prec_round_ref(&x, prec, rm)
843 }
844
845 /// Computes $\operatorname{asech} x$, the inverse hyperbolic secant of a [`Rational`], rounding
846 /// the result to the specified precision and with the specified rounding mode and returning the
847 /// result as a [`Float`]. The [`Rational`] is taken by reference. An [`Ordering`] is also
848 /// returned, indicating whether the rounded inverse hyperbolic secant is less than, equal to,
849 /// or greater than the exact inverse hyperbolic secant. Although `NaN`s are not comparable to
850 /// any [`Float`], whenever this function returns a `NaN` it also returns `Equal`.
851 ///
852 /// See [`RoundingMode`] for a description of the possible rounding modes.
853 ///
854 /// $$
855 /// f(x,p,m) = \operatorname{asech} x+\varepsilon.
856 /// $$
857 /// - If $\operatorname{asech} x$ is infinite, zero, or NaN, $\varepsilon$ may be ignored or
858 /// assumed to be 0.
859 /// - If $\operatorname{asech} x$ is finite and nonzero, and $m$ is not `Nearest`, then
860 /// $|\varepsilon| < 2^{\lfloor\log_2 \operatorname{asech} x\rfloor-p+1}$.
861 /// - If $\operatorname{asech} x$ is finite and nonzero, and $m$ is `Nearest`, then
862 /// $|\varepsilon| \leq 2^{\lfloor\log_2 \operatorname{asech} x\rfloor-p}$.
863 ///
864 /// These bounds do not apply when the result underflows; see below.
865 ///
866 /// If the output has a precision, it is `prec`.
867 ///
868 /// Special cases:
869 /// - $f(0,p,m)=\infty$
870 /// - $f(1,p,m)=0.0$
871 /// - $f(x,p,m)=\text{NaN}$ if $x<0$ or $x>1$
872 ///
873 /// Overflow and underflow:
874 /// - The result never overflows: for $0<x<1$ with denominator $d$, $\operatorname{asech} x <
875 /// \ln(2/x) \leq \ln 2d$.
876 /// - If $0<f(x,p,m)<2^{-2^{30}}$, and $m$ is `Floor` or `Down`, $0.0$ is returned instead.
877 /// - If $0<f(x,p,m)<2^{-2^{30}}$, and $m$ is `Ceiling` or `Up`, $2^{-2^{30}}$ is returned
878 /// instead.
879 /// - If $0<f(x,p,m)\leq2^{-2^{30}-1}$, and $m$ is `Nearest`, $0.0$ is returned instead.
880 /// - If $2^{-2^{30}-1}<f(x,p,m)<2^{-2^{30}}$, and $m$ is `Nearest`, $2^{-2^{30}}$ is returned
881 /// instead.
882 ///
883 /// Underflow requires an $x$ within $2^{-2^{31}}$ of 1, since $\operatorname{asech}(1-t) >
884 /// \sqrt t$, and so a denominator of more than $2^{31}$ bits.
885 ///
886 /// If you know you'll be using `Nearest`, consider using [`Float::asech_rational_prec_ref`]
887 /// instead.
888 ///
889 /// # Worst-case complexity
890 /// $T(n, m) = O(n (\log n)^2 \log\log n + m (\log m)^2 \log\log m)$
891 ///
892 /// $M(n, m) = O(n \log n + m \log m)$
893 ///
894 /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
895 /// `x.significant_bits()`: the logarithm is computed at a working precision of about $n$, and
896 /// the input is handled with `Rational` arithmetic.
897 ///
898 /// # Panics
899 /// Panics if `prec` is zero, or if `rm` is `Exact` but the result cannot be represented exactly
900 /// with the given precision (which is the case for every $x$ with $0<x<1$).
901 ///
902 /// # Examples
903 /// ```
904 /// use malachite_base::rounding_modes::RoundingMode::*;
905 /// use malachite_float::Float;
906 /// use malachite_q::Rational;
907 /// use std::cmp::Ordering::*;
908 ///
909 /// let (c, o) =
910 /// Float::asech_rational_prec_round_ref(&Rational::from_unsigneds(1u8, 3), 5, Floor);
911 /// assert_eq!(c.to_string(), "1.75");
912 /// assert_eq!(o, Less);
913 ///
914 /// let (c, o) =
915 /// Float::asech_rational_prec_round_ref(&Rational::from_unsigneds(1u8, 3), 5, Ceiling);
916 /// assert_eq!(c.to_string(), "1.81");
917 /// assert_eq!(o, Greater);
918 ///
919 /// let (c, o) =
920 /// Float::asech_rational_prec_round_ref(&Rational::from_unsigneds(1u8, 3), 20, Floor);
921 /// assert_eq!(c.to_string(), "1.7627468");
922 /// assert_eq!(o, Less);
923 ///
924 /// let (c, o) =
925 /// Float::asech_rational_prec_round_ref(&Rational::from_unsigneds(1u8, 3), 20, Ceiling);
926 /// assert_eq!(c.to_string(), "1.7627487");
927 /// assert_eq!(o, Greater);
928 /// ```
929 pub fn asech_rational_prec_round_ref(
930 x: &Rational,
931 prec: u64,
932 rm: RoundingMode,
933 ) -> (Self, Ordering) {
934 assert_ne!(prec, 0);
935 match x.sign() {
936 // asech is NaN below 0
937 Less => (Self::NAN, Equal),
938 // asech(0) = +Inf
939 Equal => (Self::INFINITY, Equal),
940 // asech(x) = acosh(1/x), and the reciprocal of a `Rational` is exact
941 Greater => Self::acosh_rational_prec_round(x.reciprocal(), prec, rm),
942 }
943 }
944
945 /// Computes $\operatorname{asech} x$, the inverse hyperbolic secant of a [`Rational`], rounding
946 /// the result to the nearest value of the specified precision and returning the result as a
947 /// [`Float`]. The [`Rational`] is taken by value. An [`Ordering`] is also returned, indicating
948 /// whether the rounded inverse hyperbolic secant is less than, equal to, or greater than the
949 /// exact inverse hyperbolic secant. Although `NaN`s are not comparable to any [`Float`],
950 /// whenever this function returns a `NaN` it also returns `Equal`.
951 ///
952 /// If the inverse hyperbolic secant is equidistant from two [`Float`]s with the specified
953 /// precision, the [`Float`] with fewer 1s in its binary expansion is chosen. See
954 /// [`RoundingMode`] for a description of the `Nearest` rounding mode.
955 ///
956 /// $$
957 /// f(x,p) = \operatorname{asech} x+\varepsilon,
958 /// $$
959 /// where, if $\operatorname{asech} x$ is finite and nonzero, $|\varepsilon| \leq
960 /// 2^{\lfloor\log_2 \operatorname{asech} x\rfloor-p}$ (unless the result underflows; see
961 /// below).
962 ///
963 /// If the output has a precision, it is `prec`.
964 ///
965 /// Special cases:
966 /// - $f(0,p)=\infty$
967 /// - $f(1,p)=0.0$
968 /// - $f(x,p)=\text{NaN}$ if $x<0$ or $x>1$
969 ///
970 /// Overflow and underflow:
971 /// - The result never overflows: for $0<x<1$ with denominator $d$, $\operatorname{asech} x <
972 /// \ln(2/x) \leq \ln 2d$.
973 /// - If $0<f(x,p)\leq2^{-2^{30}-1}$, $0.0$ is returned instead.
974 /// - If $2^{-2^{30}-1}<f(x,p)<2^{-2^{30}}$, $2^{-2^{30}}$ is returned instead.
975 ///
976 /// Underflow requires an $x$ within $2^{-2^{31}}$ of 1, since $\operatorname{asech}(1-t) >
977 /// \sqrt t$, and so a denominator of more than $2^{31}$ bits.
978 ///
979 /// If you want to use a rounding mode other than `Nearest`, consider using
980 /// [`Float::asech_rational_prec_round`] instead.
981 ///
982 /// # Worst-case complexity
983 /// $T(n, m) = O(n (\log n)^2 \log\log n + m (\log m)^2 \log\log m)$
984 ///
985 /// $M(n, m) = O(n \log n + m \log m)$
986 ///
987 /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
988 /// `x.significant_bits()`: the logarithm is computed at a working precision of about $n$, and
989 /// the input is handled with `Rational` arithmetic.
990 ///
991 /// # Panics
992 /// Panics if `prec` is zero.
993 ///
994 /// # Examples
995 /// ```
996 /// use malachite_base::num::basic::traits::{One, Two, Zero};
997 /// use malachite_float::Float;
998 /// use malachite_q::Rational;
999 /// use std::cmp::Ordering::*;
1000 ///
1001 /// let (c, o) = Float::asech_rational_prec(Rational::from_unsigneds(1u8, 3), 5);
1002 /// assert_eq!(c.to_string(), "1.75");
1003 /// assert_eq!(o, Less);
1004 ///
1005 /// let (c, o) = Float::asech_rational_prec(Rational::from_unsigneds(1u8, 3), 20);
1006 /// assert_eq!(c.to_string(), "1.7627468");
1007 /// assert_eq!(o, Less);
1008 ///
1009 /// let (c, o) = Float::asech_rational_prec(Rational::ONE, 10);
1010 /// assert_eq!(c.to_string(), "0.0");
1011 /// assert_eq!(o, Equal);
1012 ///
1013 /// let (c, o) = Float::asech_rational_prec(Rational::ZERO, 10);
1014 /// assert_eq!(c.to_string(), "Infinity");
1015 /// assert_eq!(o, Equal);
1016 ///
1017 /// let (c, o) = Float::asech_rational_prec(Rational::TWO, 10);
1018 /// assert!(c.is_nan());
1019 /// assert_eq!(o, Equal);
1020 /// ```
1021 #[inline]
1022 #[allow(clippy::needless_pass_by_value)]
1023 pub fn asech_rational_prec(x: Rational, prec: u64) -> (Self, Ordering) {
1024 Self::asech_rational_prec_round_ref(&x, prec, Nearest)
1025 }
1026
1027 /// Computes $\operatorname{asech} x$, the inverse hyperbolic secant of a [`Rational`], rounding
1028 /// the result to the nearest value of the specified precision and returning the result as a
1029 /// [`Float`]. The [`Rational`] is taken by reference. An [`Ordering`] is also returned,
1030 /// indicating whether the rounded inverse hyperbolic secant is less than, equal to, or greater
1031 /// than the exact inverse hyperbolic secant. Although `NaN`s are not comparable to any
1032 /// [`Float`], whenever this function returns a `NaN` it also returns `Equal`.
1033 ///
1034 /// If the inverse hyperbolic secant is equidistant from two [`Float`]s with the specified
1035 /// precision, the [`Float`] with fewer 1s in its binary expansion is chosen. See
1036 /// [`RoundingMode`] for a description of the `Nearest` rounding mode.
1037 ///
1038 /// $$
1039 /// f(x,p) = \operatorname{asech} x+\varepsilon,
1040 /// $$
1041 /// where, if $\operatorname{asech} x$ is finite and nonzero, $|\varepsilon| \leq
1042 /// 2^{\lfloor\log_2 \operatorname{asech} x\rfloor-p}$ (unless the result underflows; see
1043 /// below).
1044 ///
1045 /// If the output has a precision, it is `prec`.
1046 ///
1047 /// Special cases:
1048 /// - $f(0,p)=\infty$
1049 /// - $f(1,p)=0.0$
1050 /// - $f(x,p)=\text{NaN}$ if $x<0$ or $x>1$
1051 ///
1052 /// Overflow and underflow:
1053 /// - The result never overflows: for $0<x<1$ with denominator $d$, $\operatorname{asech} x <
1054 /// \ln(2/x) \leq \ln 2d$.
1055 /// - If $0<f(x,p)\leq2^{-2^{30}-1}$, $0.0$ is returned instead.
1056 /// - If $2^{-2^{30}-1}<f(x,p)<2^{-2^{30}}$, $2^{-2^{30}}$ is returned instead.
1057 ///
1058 /// Underflow requires an $x$ within $2^{-2^{31}}$ of 1, since $\operatorname{asech}(1-t) >
1059 /// \sqrt t$, and so a denominator of more than $2^{31}$ bits.
1060 ///
1061 /// If you want to use a rounding mode other than `Nearest`, consider using
1062 /// [`Float::asech_rational_prec_round_ref`] instead.
1063 ///
1064 /// # Worst-case complexity
1065 /// $T(n, m) = O(n (\log n)^2 \log\log n + m (\log m)^2 \log\log m)$
1066 ///
1067 /// $M(n, m) = O(n \log n + m \log m)$
1068 ///
1069 /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
1070 /// `x.significant_bits()`: the logarithm is computed at a working precision of about $n$, and
1071 /// the input is handled with `Rational` arithmetic.
1072 ///
1073 /// # Panics
1074 /// Panics if `prec` is zero.
1075 ///
1076 /// # Examples
1077 /// ```
1078 /// use malachite_base::num::basic::traits::{One, Two, Zero};
1079 /// use malachite_float::Float;
1080 /// use malachite_q::Rational;
1081 /// use std::cmp::Ordering::*;
1082 ///
1083 /// let (c, o) = Float::asech_rational_prec_ref(&Rational::from_unsigneds(1u8, 3), 5);
1084 /// assert_eq!(c.to_string(), "1.75");
1085 /// assert_eq!(o, Less);
1086 ///
1087 /// let (c, o) = Float::asech_rational_prec_ref(&Rational::from_unsigneds(1u8, 3), 20);
1088 /// assert_eq!(c.to_string(), "1.7627468");
1089 /// assert_eq!(o, Less);
1090 ///
1091 /// let (c, o) = Float::asech_rational_prec_ref(&Rational::ONE, 10);
1092 /// assert_eq!(c.to_string(), "0.0");
1093 /// assert_eq!(o, Equal);
1094 ///
1095 /// let (c, o) = Float::asech_rational_prec_ref(&Rational::ZERO, 10);
1096 /// assert_eq!(c.to_string(), "Infinity");
1097 /// assert_eq!(o, Equal);
1098 ///
1099 /// let (c, o) = Float::asech_rational_prec_ref(&Rational::TWO, 10);
1100 /// assert!(c.is_nan());
1101 /// assert_eq!(o, Equal);
1102 /// ```
1103 #[inline]
1104 pub fn asech_rational_prec_ref(x: &Rational, prec: u64) -> (Self, Ordering) {
1105 Self::asech_rational_prec_round_ref(x, prec, Nearest)
1106 }
1107}
1108
1109impl Asech for Float {
1110 type Output = Self;
1111
1112 /// Computes $\operatorname{asech} x$, the inverse hyperbolic secant of a [`Float`], taking it
1113 /// by value.
1114 ///
1115 /// If the output has a precision, it is the precision of the input. If the inverse hyperbolic
1116 /// secant is equidistant from two [`Float`]s with the specified precision, the [`Float`] with
1117 /// fewer 1s in its binary expansion is chosen. See [`RoundingMode`] for a description of the
1118 /// `Nearest` rounding mode.
1119 ///
1120 /// $$
1121 /// f(x) = \operatorname{asech} x+\varepsilon.
1122 /// $$
1123 /// - If $\operatorname{asech} x$ is infinite, zero, or NaN, $\varepsilon$ may be ignored or
1124 /// assumed to be 0.
1125 /// - If $\operatorname{asech} x$ is finite and nonzero, then $|\varepsilon| < 2^{\lfloor\log_2
1126 /// \operatorname{asech} x\rfloor-p}$, where $p$ is the precision of the input.
1127 ///
1128 /// Special cases:
1129 /// - $f(\text{NaN})=\text{NaN}$
1130 /// - $f(\pm\infty)=\text{NaN}$
1131 /// - $f(\pm0.0)=\infty$
1132 /// - $f(1)=0.0$
1133 /// - $f(x)=\text{NaN}$ if $x<0$ or $x>1$
1134 ///
1135 /// See the [`Float::asech_round`] documentation for information on overflow and underflow.
1136 ///
1137 /// If you want to use a rounding mode other than `Nearest`, consider using
1138 /// [`Float::asech_round`] instead. If you want to specify the output precision, consider using
1139 /// [`Float::asech_prec`]. If you want both of these things, consider using
1140 /// [`Float::asech_prec_round`].
1141 ///
1142 /// # Worst-case complexity
1143 /// $T(n) = O(n (\log n)^2 \log\log n)$
1144 ///
1145 /// $M(n) = O(n \log n)$
1146 ///
1147 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
1148 ///
1149 /// # Examples
1150 /// ```
1151 /// use malachite_base::num::arithmetic::traits::Asech;
1152 /// use malachite_base::num::basic::traits::*;
1153 /// use malachite_float::Float;
1154 ///
1155 /// assert!(Float::NAN.asech().is_nan());
1156 /// assert!(Float::INFINITY.asech().is_nan());
1157 /// assert!(Float::NEGATIVE_INFINITY.asech().is_nan());
1158 /// assert_eq!(Float::ZERO.asech().to_string(), "Infinity");
1159 /// assert_eq!(Float::NEGATIVE_ZERO.asech().to_string(), "Infinity");
1160 /// assert_eq!(Float::ONE.asech().to_string(), "0.0");
1161 /// assert!(Float::TWO.asech().is_nan());
1162 /// assert!(Float::NEGATIVE_ONE.asech().is_nan());
1163 /// assert_eq!(
1164 /// (Float::one_prec(100) >> 1u32).asech().to_string(),
1165 /// "1.3169578969248167086250463473073"
1166 /// );
1167 /// assert_eq!(
1168 /// (Float::one_prec(100) >> 2u32).asech().to_string(),
1169 /// "2.0634370688955605467272811726205"
1170 /// );
1171 /// ```
1172 #[inline]
1173 fn asech(self) -> Self {
1174 let prec = self.significant_bits();
1175 self.asech_prec_round(prec, Nearest).0
1176 }
1177}
1178
1179impl Asech for &Float {
1180 type Output = Float;
1181
1182 /// Computes $\operatorname{asech} x$, the inverse hyperbolic secant of a [`Float`], taking it
1183 /// by reference.
1184 ///
1185 /// If the output has a precision, it is the precision of the input. If the inverse hyperbolic
1186 /// secant is equidistant from two [`Float`]s with the specified precision, the [`Float`] with
1187 /// fewer 1s in its binary expansion is chosen. See [`RoundingMode`] for a description of the
1188 /// `Nearest` rounding mode.
1189 ///
1190 /// $$
1191 /// f(x) = \operatorname{asech} x+\varepsilon.
1192 /// $$
1193 /// - If $\operatorname{asech} x$ is infinite, zero, or NaN, $\varepsilon$ may be ignored or
1194 /// assumed to be 0.
1195 /// - If $\operatorname{asech} x$ is finite and nonzero, then $|\varepsilon| < 2^{\lfloor\log_2
1196 /// \operatorname{asech} x\rfloor-p}$, where $p$ is the precision of the input.
1197 ///
1198 /// Special cases:
1199 /// - $f(\text{NaN})=\text{NaN}$
1200 /// - $f(\pm\infty)=\text{NaN}$
1201 /// - $f(\pm0.0)=\infty$
1202 /// - $f(1)=0.0$
1203 /// - $f(x)=\text{NaN}$ if $x<0$ or $x>1$
1204 ///
1205 /// See the [`Float::asech_round`] documentation for information on overflow and underflow.
1206 ///
1207 /// If you want to use a rounding mode other than `Nearest`, consider using
1208 /// [`Float::asech_round_ref`] instead. If you want to specify the output precision, consider
1209 /// using [`Float::asech_prec_ref`]. If you want both of these things, consider using
1210 /// [`Float::asech_prec_round_ref`].
1211 ///
1212 /// # Worst-case complexity
1213 /// $T(n) = O(n (\log n)^2 \log\log n)$
1214 ///
1215 /// $M(n) = O(n \log n)$
1216 ///
1217 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
1218 ///
1219 /// # Examples
1220 /// ```
1221 /// use malachite_base::num::arithmetic::traits::Asech;
1222 /// use malachite_base::num::basic::traits::*;
1223 /// use malachite_float::Float;
1224 ///
1225 /// assert!((&Float::NAN).asech().is_nan());
1226 /// assert!((&Float::INFINITY).asech().is_nan());
1227 /// assert!((&Float::NEGATIVE_INFINITY).asech().is_nan());
1228 /// assert_eq!((&Float::ZERO).asech().to_string(), "Infinity");
1229 /// assert_eq!((&Float::NEGATIVE_ZERO).asech().to_string(), "Infinity");
1230 /// assert_eq!((&Float::ONE).asech().to_string(), "0.0");
1231 /// assert!((&Float::TWO).asech().is_nan());
1232 /// assert!((&Float::NEGATIVE_ONE).asech().is_nan());
1233 /// assert_eq!(
1234 /// (&(Float::one_prec(100) >> 1u32)).asech().to_string(),
1235 /// "1.3169578969248167086250463473073"
1236 /// );
1237 /// assert_eq!(
1238 /// (&(Float::one_prec(100) >> 2u32)).asech().to_string(),
1239 /// "2.0634370688955605467272811726205"
1240 /// );
1241 /// ```
1242 #[inline]
1243 fn asech(self) -> Float {
1244 self.asech_prec_round_ref(self.significant_bits(), Nearest)
1245 .0
1246 }
1247}
1248
1249impl AsechAssign for Float {
1250 /// Computes $\operatorname{asech} x$, the inverse hyperbolic secant of a [`Float`], in place.
1251 ///
1252 /// If the output has a precision, it is the precision of the input. If the inverse hyperbolic
1253 /// secant is equidistant from two [`Float`]s with the specified precision, the [`Float`] with
1254 /// fewer 1s in its binary expansion is chosen. See [`RoundingMode`] for a description of the
1255 /// `Nearest` rounding mode.
1256 ///
1257 /// $$
1258 /// x \gets \operatorname{asech} x+\varepsilon.
1259 /// $$
1260 /// - If $\operatorname{asech} x$ is infinite, zero, or NaN, $\varepsilon$ may be ignored or
1261 /// assumed to be 0.
1262 /// - If $\operatorname{asech} x$ is finite and nonzero, then $|\varepsilon| < 2^{\lfloor\log_2
1263 /// \operatorname{asech} x\rfloor-p}$, where $p$ is the precision of the input.
1264 ///
1265 /// See the [`Float::asech`] documentation for information on special cases, overflow, and
1266 /// underflow.
1267 ///
1268 /// If you want to use a rounding mode other than `Nearest`, consider using
1269 /// [`Float::asech_round_assign`] instead. If you want to specify the output precision, consider
1270 /// using [`Float::asech_prec_assign`]. If you want both of these things, consider using
1271 /// [`Float::asech_prec_round_assign`].
1272 ///
1273 /// # Worst-case complexity
1274 /// $T(n) = O(n (\log n)^2 \log\log n)$
1275 ///
1276 /// $M(n) = O(n \log n)$
1277 ///
1278 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
1279 ///
1280 /// # Examples
1281 /// ```
1282 /// use malachite_base::num::arithmetic::traits::AsechAssign;
1283 /// use malachite_base::num::basic::traits::*;
1284 /// use malachite_float::Float;
1285 ///
1286 /// let mut x = Float::NAN;
1287 /// x.asech_assign();
1288 /// assert!(x.is_nan());
1289 ///
1290 /// let mut x = Float::INFINITY;
1291 /// x.asech_assign();
1292 /// assert!(x.is_nan());
1293 ///
1294 /// let mut x = Float::ZERO;
1295 /// x.asech_assign();
1296 /// assert_eq!(x.to_string(), "Infinity");
1297 ///
1298 /// let mut x = Float::NEGATIVE_ZERO;
1299 /// x.asech_assign();
1300 /// assert_eq!(x.to_string(), "Infinity");
1301 ///
1302 /// let mut x = Float::ONE;
1303 /// x.asech_assign();
1304 /// assert_eq!(x.to_string(), "0.0");
1305 ///
1306 /// let mut x = Float::TWO;
1307 /// x.asech_assign();
1308 /// assert!(x.is_nan());
1309 ///
1310 /// let mut x = Float::one_prec(100) >> 1u32;
1311 /// x.asech_assign();
1312 /// assert_eq!(x.to_string(), "1.3169578969248167086250463473073");
1313 ///
1314 /// let mut x = Float::one_prec(100) >> 2u32;
1315 /// x.asech_assign();
1316 /// assert_eq!(x.to_string(), "2.0634370688955605467272811726205");
1317 /// ```
1318 #[inline]
1319 fn asech_assign(&mut self) {
1320 let prec = self.significant_bits();
1321 self.asech_prec_round_assign(prec, Nearest);
1322 }
1323}
1324
1325/// Computes $\operatorname{asech} x$, the inverse hyperbolic secant of a primitive float. Using
1326/// this function is more accurate than using the default `asech` function or the one provided by
1327/// `libm`.
1328///
1329/// $$
1330/// f(x) = \operatorname{asech} x+\varepsilon.
1331/// $$
1332/// - If $\operatorname{asech} x$ is infinite, zero, or NaN, $\varepsilon$ may be ignored or assumed
1333/// to be 0.
1334/// - If $\operatorname{asech} x$ is finite and nonzero, then $|\varepsilon| < 2^{\lfloor\log_2
1335/// \operatorname{asech} x\rfloor-p}$, where $p$ is the precision of the output (24 if `T` is a
1336/// [`f32`] and 53 if `T` is a [`f64`]).
1337///
1338/// Special cases:
1339/// - $f(\text{NaN})=\text{NaN}$
1340/// - $f(\pm\infty)=\text{NaN}$
1341/// - $f(\pm0.0)=\infty$
1342/// - $f(1)=0.0$
1343/// - $f(x)=\text{NaN}$ if $x<0$ or $x>1$
1344///
1345/// Overflow is not possible. The result is subnormal only when $x$ is, and then it is $x$ itself,
1346/// since $|\operatorname{asech} x - x| < |x|^3/2$.
1347///
1348/// # Worst-case complexity
1349/// Constant time and additional memory.
1350///
1351/// # Examples
1352/// ```
1353/// use malachite_base::num::basic::traits::NegativeInfinity;
1354/// use malachite_base::num::float::NiceFloat;
1355/// use malachite_float::float::arithmetic::asech::primitive_float_asech;
1356///
1357/// assert!(primitive_float_asech(f32::NAN).is_nan());
1358/// assert!(primitive_float_asech(f32::INFINITY).is_nan());
1359/// assert!(primitive_float_asech(f32::NEGATIVE_INFINITY).is_nan());
1360/// assert_eq!(
1361/// NiceFloat(primitive_float_asech(0.0f32)),
1362/// NiceFloat(f32::INFINITY)
1363/// );
1364/// assert_eq!(NiceFloat(primitive_float_asech(1.0f32)), NiceFloat(0.0));
1365/// assert!(primitive_float_asech(2.0f32).is_nan());
1366/// assert_eq!(
1367/// NiceFloat(primitive_float_asech(0.5f32)),
1368/// NiceFloat(1.316958)
1369/// );
1370/// assert_eq!(
1371/// NiceFloat(primitive_float_asech(0.5f64)),
1372/// NiceFloat(1.3169578969248168)
1373/// );
1374/// assert_eq!(
1375/// NiceFloat(primitive_float_asech(0.1f64)),
1376/// NiceFloat(2.993222846126381)
1377/// );
1378/// ```
1379#[inline]
1380#[allow(clippy::type_repetition_in_bounds)]
1381pub fn primitive_float_asech<T: PrimitiveFloat>(x: T) -> T
1382where
1383 Float: From<T> + PartialOrd<T>,
1384 for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
1385{
1386 emulate_float_to_float_fn(Float::asech_prec, x)
1387}
1388
1389/// Computes $\operatorname{asech} x$, the inverse hyperbolic secant of a [`Rational`], returning
1390/// the result as a primitive float. The result is correctly rounded.
1391///
1392/// $$
1393/// f(x) = \operatorname{asech} x+\varepsilon.
1394/// $$
1395/// - If $\operatorname{asech} x$ is infinite, zero, or NaN, $\varepsilon$ may be ignored or assumed
1396/// to be 0.
1397/// - If $\operatorname{asech} x$ is finite and nonzero, then $|\varepsilon| < 2^{\lfloor\log_2
1398/// \operatorname{asech} x\rfloor-p}$, where $p$ is the precision of the output (typically 24 if
1399/// `T` is a [`f32`] and 53 if `T` is a [`f64`], but less if the output is subnormal).
1400///
1401/// Special cases:
1402/// - $f(0)=\infty$
1403/// - $f(1)=0.0$
1404/// - $f(x)=\text{NaN}$ if $x<0$ or $x>1$
1405///
1406/// Overflow is not possible. Underflow is: an `x` close enough to 1 gives `0.0`.
1407///
1408/// # Worst-case complexity
1409/// $T(m) = O(m (\log m)^2 \log\log m)$
1410///
1411/// $M(m) = O(m \log m)$
1412///
1413/// where $T$ is time, $M$ is additional memory, and $m$ is `x.significant_bits()`.
1414///
1415/// # Examples
1416/// ```
1417/// use malachite_base::num::basic::traits::{One, Two, Zero};
1418/// use malachite_base::num::float::NiceFloat;
1419/// use malachite_float::float::arithmetic::asech::primitive_float_asech_rational;
1420/// use malachite_q::Rational;
1421///
1422/// assert_eq!(
1423/// NiceFloat(primitive_float_asech_rational::<f64>(&Rational::ZERO)),
1424/// NiceFloat(f64::INFINITY)
1425/// );
1426/// assert_eq!(
1427/// NiceFloat(primitive_float_asech_rational::<f64>(&Rational::ONE)),
1428/// NiceFloat(0.0)
1429/// );
1430/// assert!(primitive_float_asech_rational::<f64>(&Rational::TWO).is_nan());
1431/// assert_eq!(
1432/// NiceFloat(primitive_float_asech_rational::<f64>(
1433/// &Rational::from_unsigneds(1u8, 3)
1434/// )),
1435/// NiceFloat(1.762747174039086)
1436/// );
1437/// ```
1438#[inline]
1439#[allow(clippy::type_repetition_in_bounds)]
1440pub fn primitive_float_asech_rational<T: PrimitiveFloat>(x: &Rational) -> T
1441where
1442 Float: PartialOrd<T>,
1443 for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
1444{
1445 emulate_rational_to_float_fn(Float::asech_rational_prec_ref, x)
1446}