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