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