std/num/
f16.rs

1//! Constants for the `f16` half-precision floating point type.
2//!
3//! *[See also the `f16` primitive type](primitive@f16).*
4//!
5//! Mathematically significant numbers are provided in the `consts` sub-module.
6
7#![unstable(feature = "f16", issue = "116909")]
8#![doc(test(attr(feature(cfg_target_has_reliable_f16_f128), expect(internal_features))))]
9
10#[unstable(feature = "f16", issue = "116909")]
11pub use core::f16::consts;
12
13#[cfg(not(test))]
14use crate::intrinsics;
15#[cfg(not(test))]
16use crate::sys::cmath;
17
18#[cfg(not(test))]
19impl f16 {
20    /// Raises a number to a floating point power.
21    ///
22    /// Note that this function is special in that it can return non-NaN results for NaN inputs. For
23    /// example, `f16::powf(f16::NAN, 0.0)` returns `1.0`. However, if an input is a *signaling*
24    /// NaN, then the result is non-deterministically either a NaN or the result that the
25    /// corresponding quiet NaN would produce.
26    ///
27    /// # Unspecified precision
28    ///
29    /// The precision of this function is non-deterministic. This means it varies by platform,
30    /// Rust version, and can even differ within the same execution from one invocation to the next.
31    ///
32    /// # Examples
33    ///
34    /// ```
35    /// #![feature(f16)]
36    /// # #[cfg(not(miri))]
37    /// # #[cfg(target_has_reliable_f16_math)] {
38    ///
39    /// let x = 2.0_f16;
40    /// let abs_difference = (x.powf(2.0) - (x * x)).abs();
41    /// assert!(abs_difference <= f16::EPSILON);
42    ///
43    /// assert_eq!(f16::powf(1.0, f16::NAN), 1.0);
44    /// assert_eq!(f16::powf(f16::NAN, 0.0), 1.0);
45    /// assert_eq!(f16::powf(0.0, 0.0), 1.0);
46    /// # }
47    /// ```
48    #[inline]
49    #[rustc_allow_incoherent_impl]
50    #[unstable(feature = "f16", issue = "116909")]
51    #[must_use = "method returns a new number and does not mutate the original value"]
52    pub fn powf(self, n: f16) -> f16 {
53        intrinsics::powf16(self, n)
54    }
55
56    /// Returns `e^(self)`, (the exponential function).
57    ///
58    /// # Unspecified precision
59    ///
60    /// The precision of this function is non-deterministic. This means it varies by platform,
61    /// Rust version, and can even differ within the same execution from one invocation to the next.
62    ///
63    /// # Examples
64    ///
65    /// ```
66    /// #![feature(f16)]
67    /// # #[cfg(not(miri))]
68    /// # #[cfg(target_has_reliable_f16_math)] {
69    ///
70    /// let one = 1.0f16;
71    /// // e^1
72    /// let e = one.exp();
73    ///
74    /// // ln(e) - 1 == 0
75    /// let abs_difference = (e.ln() - 1.0).abs();
76    ///
77    /// assert!(abs_difference <= f16::EPSILON);
78    /// # }
79    /// ```
80    #[inline]
81    #[rustc_allow_incoherent_impl]
82    #[unstable(feature = "f16", issue = "116909")]
83    #[must_use = "method returns a new number and does not mutate the original value"]
84    pub fn exp(self) -> f16 {
85        intrinsics::expf16(self)
86    }
87
88    /// Returns `2^(self)`.
89    ///
90    /// # Unspecified precision
91    ///
92    /// The precision of this function is non-deterministic. This means it varies by platform,
93    /// Rust version, and can even differ within the same execution from one invocation to the next.
94    ///
95    /// # Examples
96    ///
97    /// ```
98    /// #![feature(f16)]
99    /// # #[cfg(not(miri))]
100    /// # #[cfg(target_has_reliable_f16_math)] {
101    ///
102    /// let f = 2.0f16;
103    ///
104    /// // 2^2 - 4 == 0
105    /// let abs_difference = (f.exp2() - 4.0).abs();
106    ///
107    /// assert!(abs_difference <= f16::EPSILON);
108    /// # }
109    /// ```
110    #[inline]
111    #[rustc_allow_incoherent_impl]
112    #[unstable(feature = "f16", issue = "116909")]
113    #[must_use = "method returns a new number and does not mutate the original value"]
114    pub fn exp2(self) -> f16 {
115        intrinsics::exp2f16(self)
116    }
117
118    /// Returns the natural logarithm of the number.
119    ///
120    /// This returns NaN when the number is negative, and negative infinity when number is zero.
121    ///
122    /// # Unspecified precision
123    ///
124    /// The precision of this function is non-deterministic. This means it varies by platform,
125    /// Rust version, and can even differ within the same execution from one invocation to the next.
126    ///
127    /// # Examples
128    ///
129    /// ```
130    /// #![feature(f16)]
131    /// # #[cfg(not(miri))]
132    /// # #[cfg(target_has_reliable_f16_math)] {
133    ///
134    /// let one = 1.0f16;
135    /// // e^1
136    /// let e = one.exp();
137    ///
138    /// // ln(e) - 1 == 0
139    /// let abs_difference = (e.ln() - 1.0).abs();
140    ///
141    /// assert!(abs_difference <= f16::EPSILON);
142    /// # }
143    /// ```
144    ///
145    /// Non-positive values:
146    /// ```
147    /// #![feature(f16)]
148    /// # #[cfg(not(miri))]
149    /// # #[cfg(target_has_reliable_f16_math)] {
150    ///
151    /// assert_eq!(0_f16.ln(), f16::NEG_INFINITY);
152    /// assert!((-42_f16).ln().is_nan());
153    /// # }
154    /// ```
155    #[inline]
156    #[rustc_allow_incoherent_impl]
157    #[unstable(feature = "f16", issue = "116909")]
158    #[must_use = "method returns a new number and does not mutate the original value"]
159    pub fn ln(self) -> f16 {
160        intrinsics::logf16(self)
161    }
162
163    /// Returns the logarithm of the number with respect to an arbitrary base.
164    ///
165    /// This returns NaN when the number is negative, and negative infinity when number is zero.
166    ///
167    /// The result might not be correctly rounded owing to implementation details;
168    /// `self.log2()` can produce more accurate results for base 2, and
169    /// `self.log10()` can produce more accurate results for base 10.
170    ///
171    /// # Unspecified precision
172    ///
173    /// The precision of this function is non-deterministic. This means it varies by platform,
174    /// Rust version, and can even differ within the same execution from one invocation to the next.
175    ///
176    /// # Examples
177    ///
178    /// ```
179    /// #![feature(f16)]
180    /// # #[cfg(not(miri))]
181    /// # #[cfg(target_has_reliable_f16_math)] {
182    ///
183    /// let five = 5.0f16;
184    ///
185    /// // log5(5) - 1 == 0
186    /// let abs_difference = (five.log(5.0) - 1.0).abs();
187    ///
188    /// assert!(abs_difference <= f16::EPSILON);
189    /// # }
190    /// ```
191    ///
192    /// Non-positive values:
193    /// ```
194    /// #![feature(f16)]
195    /// # #[cfg(not(miri))]
196    /// # #[cfg(target_has_reliable_f16_math)] {
197    ///
198    /// assert_eq!(0_f16.log(10.0), f16::NEG_INFINITY);
199    /// assert!((-42_f16).log(10.0).is_nan());
200    /// # }
201    /// ```
202    #[inline]
203    #[rustc_allow_incoherent_impl]
204    #[unstable(feature = "f16", issue = "116909")]
205    #[must_use = "method returns a new number and does not mutate the original value"]
206    pub fn log(self, base: f16) -> f16 {
207        self.ln() / base.ln()
208    }
209
210    /// Returns the base 2 logarithm of the number.
211    ///
212    /// This returns NaN when the number is negative, and negative infinity when number is zero.
213    ///
214    /// # Unspecified precision
215    ///
216    /// The precision of this function is non-deterministic. This means it varies by platform,
217    /// Rust version, and can even differ within the same execution from one invocation to the next.
218    ///
219    /// # Examples
220    ///
221    /// ```
222    /// #![feature(f16)]
223    /// # #[cfg(not(miri))]
224    /// # #[cfg(target_has_reliable_f16_math)] {
225    ///
226    /// let two = 2.0f16;
227    ///
228    /// // log2(2) - 1 == 0
229    /// let abs_difference = (two.log2() - 1.0).abs();
230    ///
231    /// assert!(abs_difference <= f16::EPSILON);
232    /// # }
233    /// ```
234    ///
235    /// Non-positive values:
236    /// ```
237    /// #![feature(f16)]
238    /// # #[cfg(not(miri))]
239    /// # #[cfg(target_has_reliable_f16_math)] {
240    ///
241    /// assert_eq!(0_f16.log2(), f16::NEG_INFINITY);
242    /// assert!((-42_f16).log2().is_nan());
243    /// # }
244    /// ```
245    #[inline]
246    #[rustc_allow_incoherent_impl]
247    #[unstable(feature = "f16", issue = "116909")]
248    #[must_use = "method returns a new number and does not mutate the original value"]
249    pub fn log2(self) -> f16 {
250        intrinsics::log2f16(self)
251    }
252
253    /// Returns the base 10 logarithm of the number.
254    ///
255    /// This returns NaN when the number is negative, and negative infinity when number is zero.
256    ///
257    /// # Unspecified precision
258    ///
259    /// The precision of this function is non-deterministic. This means it varies by platform,
260    /// Rust version, and can even differ within the same execution from one invocation to the next.
261    ///
262    /// # Examples
263    ///
264    /// ```
265    /// #![feature(f16)]
266    /// # #[cfg(not(miri))]
267    /// # #[cfg(target_has_reliable_f16_math)] {
268    ///
269    /// let ten = 10.0f16;
270    ///
271    /// // log10(10) - 1 == 0
272    /// let abs_difference = (ten.log10() - 1.0).abs();
273    ///
274    /// assert!(abs_difference <= f16::EPSILON);
275    /// # }
276    /// ```
277    ///
278    /// Non-positive values:
279    /// ```
280    /// #![feature(f16)]
281    /// # #[cfg(not(miri))]
282    /// # #[cfg(target_has_reliable_f16_math)] {
283    ///
284    /// assert_eq!(0_f16.log10(), f16::NEG_INFINITY);
285    /// assert!((-42_f16).log10().is_nan());
286    /// # }
287    /// ```
288    #[inline]
289    #[rustc_allow_incoherent_impl]
290    #[unstable(feature = "f16", issue = "116909")]
291    #[must_use = "method returns a new number and does not mutate the original value"]
292    pub fn log10(self) -> f16 {
293        intrinsics::log10f16(self)
294    }
295
296    /// Compute the distance between the origin and a point (`x`, `y`) on the
297    /// Euclidean plane. Equivalently, compute the length of the hypotenuse of a
298    /// right-angle triangle with other sides having length `x.abs()` and
299    /// `y.abs()`.
300    ///
301    /// # Unspecified precision
302    ///
303    /// The precision of this function is non-deterministic. This means it varies by platform,
304    /// Rust version, and can even differ within the same execution from one invocation to the next.
305    ///
306    /// This function currently corresponds to the `hypotf` from libc on Unix
307    /// and Windows. Note that this might change in the future.
308    ///
309    /// # Examples
310    ///
311    /// ```
312    /// #![feature(f16)]
313    /// # #[cfg(not(miri))]
314    /// # #[cfg(target_has_reliable_f16_math)] {
315    ///
316    /// let x = 2.0f16;
317    /// let y = 3.0f16;
318    ///
319    /// // sqrt(x^2 + y^2)
320    /// let abs_difference = (x.hypot(y) - (x.powi(2) + y.powi(2)).sqrt()).abs();
321    ///
322    /// assert!(abs_difference <= f16::EPSILON);
323    /// # }
324    /// ```
325    #[inline]
326    #[rustc_allow_incoherent_impl]
327    #[unstable(feature = "f16", issue = "116909")]
328    #[must_use = "method returns a new number and does not mutate the original value"]
329    pub fn hypot(self, other: f16) -> f16 {
330        cmath::hypotf(self as f32, other as f32) as f16
331    }
332
333    /// Computes the sine of a number (in radians).
334    ///
335    /// # Unspecified precision
336    ///
337    /// The precision of this function is non-deterministic. This means it varies by platform,
338    /// Rust version, and can even differ within the same execution from one invocation to the next.
339    ///
340    /// # Examples
341    ///
342    /// ```
343    /// #![feature(f16)]
344    /// # #[cfg(not(miri))]
345    /// # #[cfg(target_has_reliable_f16_math)] {
346    ///
347    /// let x = std::f16::consts::FRAC_PI_2;
348    ///
349    /// let abs_difference = (x.sin() - 1.0).abs();
350    ///
351    /// assert!(abs_difference <= f16::EPSILON);
352    /// # }
353    /// ```
354    #[inline]
355    #[rustc_allow_incoherent_impl]
356    #[unstable(feature = "f16", issue = "116909")]
357    #[must_use = "method returns a new number and does not mutate the original value"]
358    pub fn sin(self) -> f16 {
359        intrinsics::sinf16(self)
360    }
361
362    /// Computes the cosine of a number (in radians).
363    ///
364    /// # Unspecified precision
365    ///
366    /// The precision of this function is non-deterministic. This means it varies by platform,
367    /// Rust version, and can even differ within the same execution from one invocation to the next.
368    ///
369    /// # Examples
370    ///
371    /// ```
372    /// #![feature(f16)]
373    /// # #[cfg(not(miri))]
374    /// # #[cfg(target_has_reliable_f16_math)] {
375    ///
376    /// let x = 2.0 * std::f16::consts::PI;
377    ///
378    /// let abs_difference = (x.cos() - 1.0).abs();
379    ///
380    /// assert!(abs_difference <= f16::EPSILON);
381    /// # }
382    /// ```
383    #[inline]
384    #[rustc_allow_incoherent_impl]
385    #[unstable(feature = "f16", issue = "116909")]
386    #[must_use = "method returns a new number and does not mutate the original value"]
387    pub fn cos(self) -> f16 {
388        intrinsics::cosf16(self)
389    }
390
391    /// Computes the tangent of a number (in radians).
392    ///
393    /// # Unspecified precision
394    ///
395    /// The precision of this function is non-deterministic. This means it varies by platform,
396    /// Rust version, and can even differ within the same execution from one invocation to the next.
397    ///
398    /// This function currently corresponds to the `tanf` from libc on Unix and
399    /// Windows. Note that this might change in the future.
400    ///
401    /// # Examples
402    ///
403    /// ```
404    /// #![feature(f16)]
405    /// # #[cfg(not(miri))]
406    /// # #[cfg(target_has_reliable_f16_math)] {
407    ///
408    /// let x = std::f16::consts::FRAC_PI_4;
409    /// let abs_difference = (x.tan() - 1.0).abs();
410    ///
411    /// assert!(abs_difference <= f16::EPSILON);
412    /// # }
413    /// ```
414    #[inline]
415    #[rustc_allow_incoherent_impl]
416    #[unstable(feature = "f16", issue = "116909")]
417    #[must_use = "method returns a new number and does not mutate the original value"]
418    pub fn tan(self) -> f16 {
419        cmath::tanf(self as f32) as f16
420    }
421
422    /// Computes the arcsine of a number. Return value is in radians in
423    /// the range [-pi/2, pi/2] or NaN if the number is outside the range
424    /// [-1, 1].
425    ///
426    /// # Unspecified precision
427    ///
428    /// The precision of this function is non-deterministic. This means it varies by platform,
429    /// Rust version, and can even differ within the same execution from one invocation to the next.
430    ///
431    /// This function currently corresponds to the `asinf` from libc on Unix
432    /// and Windows. Note that this might change in the future.
433    ///
434    /// # Examples
435    ///
436    /// ```
437    /// #![feature(f16)]
438    /// # #[cfg(not(miri))]
439    /// # #[cfg(target_has_reliable_f16_math)] {
440    ///
441    /// let f = std::f16::consts::FRAC_PI_4;
442    ///
443    /// // asin(sin(pi/2))
444    /// let abs_difference = (f.sin().asin() - f).abs();
445    ///
446    /// assert!(abs_difference <= f16::EPSILON);
447    /// # }
448    /// ```
449    #[inline]
450    #[doc(alias = "arcsin")]
451    #[rustc_allow_incoherent_impl]
452    #[unstable(feature = "f16", issue = "116909")]
453    #[must_use = "method returns a new number and does not mutate the original value"]
454    pub fn asin(self) -> f16 {
455        cmath::asinf(self as f32) as f16
456    }
457
458    /// Computes the arccosine of a number. Return value is in radians in
459    /// the range [0, pi] or NaN if the number is outside the range
460    /// [-1, 1].
461    ///
462    /// # Unspecified precision
463    ///
464    /// The precision of this function is non-deterministic. This means it varies by platform,
465    /// Rust version, and can even differ within the same execution from one invocation to the next.
466    ///
467    /// This function currently corresponds to the `acosf` from libc on Unix
468    /// and Windows. Note that this might change in the future.
469    ///
470    /// # Examples
471    ///
472    /// ```
473    /// #![feature(f16)]
474    /// # #[cfg(not(miri))]
475    /// # #[cfg(target_has_reliable_f16_math)] {
476    ///
477    /// let f = std::f16::consts::FRAC_PI_4;
478    ///
479    /// // acos(cos(pi/4))
480    /// let abs_difference = (f.cos().acos() - std::f16::consts::FRAC_PI_4).abs();
481    ///
482    /// assert!(abs_difference <= f16::EPSILON);
483    /// # }
484    /// ```
485    #[inline]
486    #[doc(alias = "arccos")]
487    #[rustc_allow_incoherent_impl]
488    #[unstable(feature = "f16", issue = "116909")]
489    #[must_use = "method returns a new number and does not mutate the original value"]
490    pub fn acos(self) -> f16 {
491        cmath::acosf(self as f32) as f16
492    }
493
494    /// Computes the arctangent of a number. Return value is in radians in the
495    /// range [-pi/2, pi/2];
496    ///
497    /// # Unspecified precision
498    ///
499    /// The precision of this function is non-deterministic. This means it varies by platform,
500    /// Rust version, and can even differ within the same execution from one invocation to the next.
501    ///
502    /// This function currently corresponds to the `atanf` from libc on Unix
503    /// and Windows. Note that this might change in the future.
504    ///
505    /// # Examples
506    ///
507    /// ```
508    /// #![feature(f16)]
509    /// # #[cfg(not(miri))]
510    /// # #[cfg(target_has_reliable_f16_math)] {
511    ///
512    /// let f = 1.0f16;
513    ///
514    /// // atan(tan(1))
515    /// let abs_difference = (f.tan().atan() - 1.0).abs();
516    ///
517    /// assert!(abs_difference <= f16::EPSILON);
518    /// # }
519    /// ```
520    #[inline]
521    #[doc(alias = "arctan")]
522    #[rustc_allow_incoherent_impl]
523    #[unstable(feature = "f16", issue = "116909")]
524    #[must_use = "method returns a new number and does not mutate the original value"]
525    pub fn atan(self) -> f16 {
526        cmath::atanf(self as f32) as f16
527    }
528
529    /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians.
530    ///
531    ///  | `x`     | `y`     | Piecewise Definition | Range         |
532    ///  |---------|---------|----------------------|---------------|
533    ///  | `>= +0` | `>= +0` | `arctan(y/x)`        | `[+0, +pi/2]` |
534    ///  | `>= +0` | `<= -0` | `arctan(y/x)`        | `[-pi/2, -0]` |
535    ///  | `<= -0` | `>= +0` | `arctan(y/x) + pi`   | `[+pi/2, +pi]`|
536    ///  | `<= -0` | `<= -0` | `arctan(y/x) - pi`   | `[-pi, -pi/2]`|
537    ///
538    /// # Unspecified precision
539    ///
540    /// The precision of this function is non-deterministic. This means it varies by platform,
541    /// Rust version, and can even differ within the same execution from one invocation to the next.
542    ///
543    /// This function currently corresponds to the `atan2f` from libc on Unix
544    /// and Windows. Note that this might change in the future.
545    ///
546    /// # Examples
547    ///
548    /// ```
549    /// #![feature(f16)]
550    /// # #[cfg(not(miri))]
551    /// # #[cfg(target_has_reliable_f16_math)] {
552    ///
553    /// // Positive angles measured counter-clockwise
554    /// // from positive x axis
555    /// // -pi/4 radians (45 deg clockwise)
556    /// let x1 = 3.0f16;
557    /// let y1 = -3.0f16;
558    ///
559    /// // 3pi/4 radians (135 deg counter-clockwise)
560    /// let x2 = -3.0f16;
561    /// let y2 = 3.0f16;
562    ///
563    /// let abs_difference_1 = (y1.atan2(x1) - (-std::f16::consts::FRAC_PI_4)).abs();
564    /// let abs_difference_2 = (y2.atan2(x2) - (3.0 * std::f16::consts::FRAC_PI_4)).abs();
565    ///
566    /// assert!(abs_difference_1 <= f16::EPSILON);
567    /// assert!(abs_difference_2 <= f16::EPSILON);
568    /// # }
569    /// ```
570    #[inline]
571    #[rustc_allow_incoherent_impl]
572    #[unstable(feature = "f16", issue = "116909")]
573    #[must_use = "method returns a new number and does not mutate the original value"]
574    pub fn atan2(self, other: f16) -> f16 {
575        cmath::atan2f(self as f32, other as f32) as f16
576    }
577
578    /// Simultaneously computes the sine and cosine of the number, `x`. Returns
579    /// `(sin(x), cos(x))`.
580    ///
581    /// # Unspecified precision
582    ///
583    /// The precision of this function is non-deterministic. This means it varies by platform,
584    /// Rust version, and can even differ within the same execution from one invocation to the next.
585    ///
586    /// This function currently corresponds to the `(f16::sin(x),
587    /// f16::cos(x))`. Note that this might change in the future.
588    ///
589    /// # Examples
590    ///
591    /// ```
592    /// #![feature(f16)]
593    /// # #[cfg(not(miri))]
594    /// # #[cfg(target_has_reliable_f16_math)] {
595    ///
596    /// let x = std::f16::consts::FRAC_PI_4;
597    /// let f = x.sin_cos();
598    ///
599    /// let abs_difference_0 = (f.0 - x.sin()).abs();
600    /// let abs_difference_1 = (f.1 - x.cos()).abs();
601    ///
602    /// assert!(abs_difference_0 <= f16::EPSILON);
603    /// assert!(abs_difference_1 <= f16::EPSILON);
604    /// # }
605    /// ```
606    #[inline]
607    #[doc(alias = "sincos")]
608    #[rustc_allow_incoherent_impl]
609    #[unstable(feature = "f16", issue = "116909")]
610    pub fn sin_cos(self) -> (f16, f16) {
611        (self.sin(), self.cos())
612    }
613
614    /// Returns `e^(self) - 1` in a way that is accurate even if the
615    /// number is close to zero.
616    ///
617    /// # Unspecified precision
618    ///
619    /// The precision of this function is non-deterministic. This means it varies by platform,
620    /// Rust version, and can even differ within the same execution from one invocation to the next.
621    ///
622    /// This function currently corresponds to the `expm1f` from libc on Unix
623    /// and Windows. Note that this might change in the future.
624    ///
625    /// # Examples
626    ///
627    /// ```
628    /// #![feature(f16)]
629    /// # #[cfg(not(miri))]
630    /// # #[cfg(target_has_reliable_f16_math)] {
631    ///
632    /// let x = 1e-4_f16;
633    ///
634    /// // for very small x, e^x is approximately 1 + x + x^2 / 2
635    /// let approx = x + x * x / 2.0;
636    /// let abs_difference = (x.exp_m1() - approx).abs();
637    ///
638    /// assert!(abs_difference < 1e-4);
639    /// # }
640    /// ```
641    #[inline]
642    #[rustc_allow_incoherent_impl]
643    #[unstable(feature = "f16", issue = "116909")]
644    #[must_use = "method returns a new number and does not mutate the original value"]
645    pub fn exp_m1(self) -> f16 {
646        cmath::expm1f(self as f32) as f16
647    }
648
649    /// Returns `ln(1+n)` (natural logarithm) more accurately than if
650    /// the operations were performed separately.
651    ///
652    /// This returns NaN when `n < -1.0`, and negative infinity when `n == -1.0`.
653    ///
654    /// # Unspecified precision
655    ///
656    /// The precision of this function is non-deterministic. This means it varies by platform,
657    /// Rust version, and can even differ within the same execution from one invocation to the next.
658    ///
659    /// This function currently corresponds to the `log1pf` from libc on Unix
660    /// and Windows. Note that this might change in the future.
661    ///
662    /// # Examples
663    ///
664    /// ```
665    /// #![feature(f16)]
666    /// # #[cfg(not(miri))]
667    /// # #[cfg(target_has_reliable_f16_math)] {
668    ///
669    /// let x = 1e-4_f16;
670    ///
671    /// // for very small x, ln(1 + x) is approximately x - x^2 / 2
672    /// let approx = x - x * x / 2.0;
673    /// let abs_difference = (x.ln_1p() - approx).abs();
674    ///
675    /// assert!(abs_difference < 1e-4);
676    /// # }
677    /// ```
678    ///
679    /// Out-of-range values:
680    /// ```
681    /// #![feature(f16)]
682    /// # #[cfg(not(miri))]
683    /// # #[cfg(target_has_reliable_f16_math)] {
684    ///
685    /// assert_eq!((-1.0_f16).ln_1p(), f16::NEG_INFINITY);
686    /// assert!((-2.0_f16).ln_1p().is_nan());
687    /// # }
688    /// ```
689    #[inline]
690    #[doc(alias = "log1p")]
691    #[rustc_allow_incoherent_impl]
692    #[unstable(feature = "f16", issue = "116909")]
693    #[must_use = "method returns a new number and does not mutate the original value"]
694    pub fn ln_1p(self) -> f16 {
695        cmath::log1pf(self as f32) as f16
696    }
697
698    /// Hyperbolic sine function.
699    ///
700    /// # Unspecified precision
701    ///
702    /// The precision of this function is non-deterministic. This means it varies by platform,
703    /// Rust version, and can even differ within the same execution from one invocation to the next.
704    ///
705    /// This function currently corresponds to the `sinhf` from libc on Unix
706    /// and Windows. Note that this might change in the future.
707    ///
708    /// # Examples
709    ///
710    /// ```
711    /// #![feature(f16)]
712    /// # #[cfg(not(miri))]
713    /// # #[cfg(target_has_reliable_f16_math)] {
714    ///
715    /// let e = std::f16::consts::E;
716    /// let x = 1.0f16;
717    ///
718    /// let f = x.sinh();
719    /// // Solving sinh() at 1 gives `(e^2-1)/(2e)`
720    /// let g = ((e * e) - 1.0) / (2.0 * e);
721    /// let abs_difference = (f - g).abs();
722    ///
723    /// assert!(abs_difference <= f16::EPSILON);
724    /// # }
725    /// ```
726    #[inline]
727    #[rustc_allow_incoherent_impl]
728    #[unstable(feature = "f16", issue = "116909")]
729    #[must_use = "method returns a new number and does not mutate the original value"]
730    pub fn sinh(self) -> f16 {
731        cmath::sinhf(self as f32) as f16
732    }
733
734    /// Hyperbolic cosine function.
735    ///
736    /// # Unspecified precision
737    ///
738    /// The precision of this function is non-deterministic. This means it varies by platform,
739    /// Rust version, and can even differ within the same execution from one invocation to the next.
740    ///
741    /// This function currently corresponds to the `coshf` from libc on Unix
742    /// and Windows. Note that this might change in the future.
743    ///
744    /// # Examples
745    ///
746    /// ```
747    /// #![feature(f16)]
748    /// # #[cfg(not(miri))]
749    /// # #[cfg(target_has_reliable_f16_math)] {
750    ///
751    /// let e = std::f16::consts::E;
752    /// let x = 1.0f16;
753    /// let f = x.cosh();
754    /// // Solving cosh() at 1 gives this result
755    /// let g = ((e * e) + 1.0) / (2.0 * e);
756    /// let abs_difference = (f - g).abs();
757    ///
758    /// // Same result
759    /// assert!(abs_difference <= f16::EPSILON);
760    /// # }
761    /// ```
762    #[inline]
763    #[rustc_allow_incoherent_impl]
764    #[unstable(feature = "f16", issue = "116909")]
765    #[must_use = "method returns a new number and does not mutate the original value"]
766    pub fn cosh(self) -> f16 {
767        cmath::coshf(self as f32) as f16
768    }
769
770    /// Hyperbolic tangent function.
771    ///
772    /// # Unspecified precision
773    ///
774    /// The precision of this function is non-deterministic. This means it varies by platform,
775    /// Rust version, and can even differ within the same execution from one invocation to the next.
776    ///
777    /// This function currently corresponds to the `tanhf` from libc on Unix
778    /// and Windows. Note that this might change in the future.
779    ///
780    /// # Examples
781    ///
782    /// ```
783    /// #![feature(f16)]
784    /// # #[cfg(not(miri))]
785    /// # #[cfg(target_has_reliable_f16_math)] {
786    ///
787    /// let e = std::f16::consts::E;
788    /// let x = 1.0f16;
789    ///
790    /// let f = x.tanh();
791    /// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))`
792    /// let g = (1.0 - e.powi(-2)) / (1.0 + e.powi(-2));
793    /// let abs_difference = (f - g).abs();
794    ///
795    /// assert!(abs_difference <= f16::EPSILON);
796    /// # }
797    /// ```
798    #[inline]
799    #[rustc_allow_incoherent_impl]
800    #[unstable(feature = "f16", issue = "116909")]
801    #[must_use = "method returns a new number and does not mutate the original value"]
802    pub fn tanh(self) -> f16 {
803        cmath::tanhf(self as f32) as f16
804    }
805
806    /// Inverse hyperbolic sine function.
807    ///
808    /// # Unspecified precision
809    ///
810    /// The precision of this function is non-deterministic. This means it varies by platform,
811    /// Rust version, and can even differ within the same execution from one invocation to the next.
812    ///
813    /// # Examples
814    ///
815    /// ```
816    /// #![feature(f16)]
817    /// # #[cfg(not(miri))]
818    /// # #[cfg(target_has_reliable_f16_math)] {
819    ///
820    /// let x = 1.0f16;
821    /// let f = x.sinh().asinh();
822    ///
823    /// let abs_difference = (f - x).abs();
824    ///
825    /// assert!(abs_difference <= f16::EPSILON);
826    /// # }
827    /// ```
828    #[inline]
829    #[doc(alias = "arcsinh")]
830    #[rustc_allow_incoherent_impl]
831    #[unstable(feature = "f16", issue = "116909")]
832    #[must_use = "method returns a new number and does not mutate the original value"]
833    pub fn asinh(self) -> f16 {
834        let ax = self.abs();
835        let ix = 1.0 / ax;
836        (ax + (ax / (Self::hypot(1.0, ix) + ix))).ln_1p().copysign(self)
837    }
838
839    /// Inverse hyperbolic cosine function.
840    ///
841    /// # Unspecified precision
842    ///
843    /// The precision of this function is non-deterministic. This means it varies by platform,
844    /// Rust version, and can even differ within the same execution from one invocation to the next.
845    ///
846    /// # Examples
847    ///
848    /// ```
849    /// #![feature(f16)]
850    /// # #[cfg(not(miri))]
851    /// # #[cfg(target_has_reliable_f16_math)] {
852    ///
853    /// let x = 1.0f16;
854    /// let f = x.cosh().acosh();
855    ///
856    /// let abs_difference = (f - x).abs();
857    ///
858    /// assert!(abs_difference <= f16::EPSILON);
859    /// # }
860    /// ```
861    #[inline]
862    #[doc(alias = "arccosh")]
863    #[rustc_allow_incoherent_impl]
864    #[unstable(feature = "f16", issue = "116909")]
865    #[must_use = "method returns a new number and does not mutate the original value"]
866    pub fn acosh(self) -> f16 {
867        if self < 1.0 {
868            Self::NAN
869        } else {
870            (self + ((self - 1.0).sqrt() * (self + 1.0).sqrt())).ln()
871        }
872    }
873
874    /// Inverse hyperbolic tangent function.
875    ///
876    /// # Unspecified precision
877    ///
878    /// The precision of this function is non-deterministic. This means it varies by platform,
879    /// Rust version, and can even differ within the same execution from one invocation to the next.
880    ///
881    /// # Examples
882    ///
883    /// ```
884    /// #![feature(f16)]
885    /// # #[cfg(not(miri))]
886    /// # #[cfg(target_has_reliable_f16_math)] {
887    ///
888    /// let x = std::f16::consts::FRAC_PI_6;
889    /// let f = x.tanh().atanh();
890    ///
891    /// let abs_difference = (f - x).abs();
892    ///
893    /// assert!(abs_difference <= 0.01);
894    /// # }
895    /// ```
896    #[inline]
897    #[doc(alias = "arctanh")]
898    #[rustc_allow_incoherent_impl]
899    #[unstable(feature = "f16", issue = "116909")]
900    #[must_use = "method returns a new number and does not mutate the original value"]
901    pub fn atanh(self) -> f16 {
902        0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
903    }
904
905    /// Gamma function.
906    ///
907    /// # Unspecified precision
908    ///
909    /// The precision of this function is non-deterministic. This means it varies by platform,
910    /// Rust version, and can even differ within the same execution from one invocation to the next.
911    ///
912    /// This function currently corresponds to the `tgammaf` from libc on Unix
913    /// and Windows. Note that this might change in the future.
914    ///
915    /// # Examples
916    ///
917    /// ```
918    /// #![feature(f16)]
919    /// #![feature(float_gamma)]
920    /// # #[cfg(not(miri))]
921    /// # #[cfg(target_has_reliable_f16_math)] {
922    ///
923    /// let x = 5.0f16;
924    ///
925    /// let abs_difference = (x.gamma() - 24.0).abs();
926    ///
927    /// assert!(abs_difference <= f16::EPSILON);
928    /// # }
929    /// ```
930    #[inline]
931    #[rustc_allow_incoherent_impl]
932    #[unstable(feature = "f16", issue = "116909")]
933    // #[unstable(feature = "float_gamma", issue = "99842")]
934    #[must_use = "method returns a new number and does not mutate the original value"]
935    pub fn gamma(self) -> f16 {
936        cmath::tgammaf(self as f32) as f16
937    }
938
939    /// Natural logarithm of the absolute value of the gamma function
940    ///
941    /// The integer part of the tuple indicates the sign of the gamma function.
942    ///
943    /// # Unspecified precision
944    ///
945    /// The precision of this function is non-deterministic. This means it varies by platform,
946    /// Rust version, and can even differ within the same execution from one invocation to the next.
947    ///
948    /// This function currently corresponds to the `lgamma_r` from libc on Unix
949    /// and Windows. Note that this might change in the future.
950    ///
951    /// # Examples
952    ///
953    /// ```
954    /// #![feature(f16)]
955    /// #![feature(float_gamma)]
956    /// # #[cfg(not(miri))]
957    /// # #[cfg(target_has_reliable_f16_math)] {
958    ///
959    /// let x = 2.0f16;
960    ///
961    /// let abs_difference = (x.ln_gamma().0 - 0.0).abs();
962    ///
963    /// assert!(abs_difference <= f16::EPSILON);
964    /// # }
965    /// ```
966    #[inline]
967    #[rustc_allow_incoherent_impl]
968    #[unstable(feature = "f16", issue = "116909")]
969    // #[unstable(feature = "float_gamma", issue = "99842")]
970    #[must_use = "method returns a new number and does not mutate the original value"]
971    pub fn ln_gamma(self) -> (f16, i32) {
972        let mut signgamp: i32 = 0;
973        let x = cmath::lgammaf_r(self as f32, &mut signgamp) as f16;
974        (x, signgamp)
975    }
976
977    /// Error function.
978    ///
979    /// # Unspecified precision
980    ///
981    /// The precision of this function is non-deterministic. This means it varies by platform,
982    /// Rust version, and can even differ within the same execution from one invocation to the next.
983    ///
984    /// This function currently corresponds to the `erff` from libc on Unix
985    /// and Windows. Note that this might change in the future.
986    ///
987    /// # Examples
988    ///
989    /// ```
990    /// #![feature(f16)]
991    /// #![feature(float_erf)]
992    /// # #[cfg(not(miri))]
993    /// # #[cfg(target_has_reliable_f16_math)] {
994    /// /// The error function relates what percent of a normal distribution lies
995    /// /// within `x` standard deviations (scaled by `1/sqrt(2)`).
996    /// fn within_standard_deviations(x: f16) -> f16 {
997    ///     (x * std::f16::consts::FRAC_1_SQRT_2).erf() * 100.0
998    /// }
999    ///
1000    /// // 68% of a normal distribution is within one standard deviation
1001    /// assert!((within_standard_deviations(1.0) - 68.269).abs() < 0.1);
1002    /// // 95% of a normal distribution is within two standard deviations
1003    /// assert!((within_standard_deviations(2.0) - 95.450).abs() < 0.1);
1004    /// // 99.7% of a normal distribution is within three standard deviations
1005    /// assert!((within_standard_deviations(3.0) - 99.730).abs() < 0.1);
1006    /// # }
1007    /// ```
1008    #[rustc_allow_incoherent_impl]
1009    #[must_use = "method returns a new number and does not mutate the original value"]
1010    #[unstable(feature = "f16", issue = "116909")]
1011    // #[unstable(feature = "float_erf", issue = "136321")]
1012    #[inline]
1013    pub fn erf(self) -> f16 {
1014        cmath::erff(self as f32) as f16
1015    }
1016
1017    /// Complementary error function.
1018    ///
1019    /// # Unspecified precision
1020    ///
1021    /// The precision of this function is non-deterministic. This means it varies by platform,
1022    /// Rust version, and can even differ within the same execution from one invocation to the next.
1023    ///
1024    /// This function currently corresponds to the `erfcf` from libc on Unix
1025    /// and Windows. Note that this might change in the future.
1026    ///
1027    /// # Examples
1028    ///
1029    /// ```
1030    /// #![feature(f16)]
1031    /// #![feature(float_erf)]
1032    /// # #[cfg(not(miri))]
1033    /// # #[cfg(target_has_reliable_f16_math)] {
1034    /// let x: f16 = 0.123;
1035    ///
1036    /// let one = x.erf() + x.erfc();
1037    /// let abs_difference = (one - 1.0).abs();
1038    ///
1039    /// assert!(abs_difference <= f16::EPSILON);
1040    /// # }
1041    /// ```
1042    #[rustc_allow_incoherent_impl]
1043    #[must_use = "method returns a new number and does not mutate the original value"]
1044    #[unstable(feature = "f16", issue = "116909")]
1045    // #[unstable(feature = "float_erf", issue = "136321")]
1046    #[inline]
1047    pub fn erfc(self) -> f16 {
1048        cmath::erfcf(self as f32) as f16
1049    }
1050}