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