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}