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