|
1 |
| -/* origin: FreeBSD /usr/src/lib/msun/src/s_fmaf.c */ |
2 |
| -/*- |
3 |
| - * Copyright (c) 2005-2011 David Schultz <[email protected]> |
4 |
| - * All rights reserved. |
5 |
| - * |
6 |
| - * Redistribution and use in source and binary forms, with or without |
7 |
| - * modification, are permitted provided that the following conditions |
8 |
| - * are met: |
9 |
| - * 1. Redistributions of source code must retain the above copyright |
10 |
| - * notice, this list of conditions and the following disclaimer. |
11 |
| - * 2. Redistributions in binary form must reproduce the above copyright |
12 |
| - * notice, this list of conditions and the following disclaimer in the |
13 |
| - * documentation and/or other materials provided with the distribution. |
14 |
| - * |
15 |
| - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
16 |
| - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 |
| - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 |
| - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
19 |
| - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
20 |
| - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
21 |
| - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
22 |
| - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
23 |
| - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
24 |
| - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
25 |
| - * SUCH DAMAGE. |
26 |
| - */ |
27 |
| - |
28 |
| -use core::f32; |
29 |
| -use core::ptr::read_volatile; |
30 |
| - |
31 |
| -use super::fenv::{ |
32 |
| - FE_INEXACT, FE_TONEAREST, FE_UNDERFLOW, feclearexcept, fegetround, feraiseexcept, fetestexcept, |
33 |
| -}; |
34 |
| - |
35 |
| -/* |
36 |
| - * Fused multiply-add: Compute x * y + z with a single rounding error. |
37 |
| - * |
38 |
| - * A double has more than twice as much precision than a float, so |
39 |
| - * direct double-precision arithmetic suffices, except where double |
40 |
| - * rounding occurs. |
41 |
| - */ |
42 |
| - |
43 | 1 | /// Floating multiply add (f32)
|
44 | 2 | ///
|
45 | 3 | /// Computes `(x*y)+z`, rounded as one ternary operation:
|
46 | 4 | /// Computes the value (as if) to infinite precision and rounds once to the result format,
|
47 | 5 | /// according to the rounding mode characterized by the value of FLT_ROUNDS.
|
48 | 6 | #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
49 |
| -pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 { |
50 |
| - let xy: f64; |
51 |
| - let mut result: f64; |
52 |
| - let mut ui: u64; |
53 |
| - let e: i32; |
54 |
| - |
55 |
| - xy = x as f64 * y as f64; |
56 |
| - result = xy + z as f64; |
57 |
| - ui = result.to_bits(); |
58 |
| - e = (ui >> 52) as i32 & 0x7ff; |
59 |
| - /* Common case: The double precision result is fine. */ |
60 |
| - if ( |
61 |
| - /* not a halfway case */ |
62 |
| - ui & 0x1fffffff) != 0x10000000 || |
63 |
| - /* NaN */ |
64 |
| - e == 0x7ff || |
65 |
| - /* exact */ |
66 |
| - (result - xy == z as f64 && result - z as f64 == xy) || |
67 |
| - /* not round-to-nearest */ |
68 |
| - fegetround() != FE_TONEAREST |
69 |
| - { |
70 |
| - /* |
71 |
| - underflow may not be raised correctly, example: |
72 |
| - fmaf(0x1p-120f, 0x1p-120f, 0x1p-149f) |
73 |
| - */ |
74 |
| - if ((0x3ff - 149)..(0x3ff - 126)).contains(&e) && fetestexcept(FE_INEXACT) != 0 { |
75 |
| - feclearexcept(FE_INEXACT); |
76 |
| - // prevent `xy + vz` from being CSE'd with `xy + z` above |
77 |
| - let vz: f32 = unsafe { read_volatile(&z) }; |
78 |
| - result = xy + vz as f64; |
79 |
| - if fetestexcept(FE_INEXACT) != 0 { |
80 |
| - feraiseexcept(FE_UNDERFLOW); |
81 |
| - } else { |
82 |
| - feraiseexcept(FE_INEXACT); |
83 |
| - } |
84 |
| - } |
85 |
| - z = result as f32; |
86 |
| - return z; |
87 |
| - } |
88 |
| - |
89 |
| - /* |
90 |
| - * If result is inexact, and exactly halfway between two float values, |
91 |
| - * we need to adjust the low-order bit in the direction of the error. |
92 |
| - */ |
93 |
| - let neg = ui >> 63 != 0; |
94 |
| - let err = if neg == (z as f64 > xy) { xy - result + z as f64 } else { z as f64 - result + xy }; |
95 |
| - if neg == (err < 0.0) { |
96 |
| - ui += 1; |
97 |
| - } else { |
98 |
| - ui -= 1; |
99 |
| - } |
100 |
| - f64::from_bits(ui) as f32 |
| 7 | +pub fn fmaf(x: f32, y: f32, z: f32) -> f32 { |
| 8 | + super::generic::fma_big(x, y, z) |
101 | 9 | }
|
102 | 10 |
|
103 | 11 | #[cfg(test)]
|
|
0 commit comments