1*c9945492SAndroid Build Coastguard Worker /* origin: FreeBSD /usr/src/lib/msun/src/s_fmaf.c */
2*c9945492SAndroid Build Coastguard Worker /*-
3*c9945492SAndroid Build Coastguard Worker * Copyright (c) 2005-2011 David Schultz <[email protected]>
4*c9945492SAndroid Build Coastguard Worker * All rights reserved.
5*c9945492SAndroid Build Coastguard Worker *
6*c9945492SAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without
7*c9945492SAndroid Build Coastguard Worker * modification, are permitted provided that the following conditions
8*c9945492SAndroid Build Coastguard Worker * are met:
9*c9945492SAndroid Build Coastguard Worker * 1. Redistributions of source code must retain the above copyright
10*c9945492SAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer.
11*c9945492SAndroid Build Coastguard Worker * 2. Redistributions in binary form must reproduce the above copyright
12*c9945492SAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer in the
13*c9945492SAndroid Build Coastguard Worker * documentation and/or other materials provided with the distribution.
14*c9945492SAndroid Build Coastguard Worker *
15*c9945492SAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16*c9945492SAndroid Build Coastguard Worker * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*c9945492SAndroid Build Coastguard Worker * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*c9945492SAndroid Build Coastguard Worker * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19*c9945492SAndroid Build Coastguard Worker * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*c9945492SAndroid Build Coastguard Worker * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*c9945492SAndroid Build Coastguard Worker * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*c9945492SAndroid Build Coastguard Worker * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*c9945492SAndroid Build Coastguard Worker * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*c9945492SAndroid Build Coastguard Worker * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*c9945492SAndroid Build Coastguard Worker * SUCH DAMAGE.
26*c9945492SAndroid Build Coastguard Worker */
27*c9945492SAndroid Build Coastguard Worker
28*c9945492SAndroid Build Coastguard Worker #include <fenv.h>
29*c9945492SAndroid Build Coastguard Worker #include <math.h>
30*c9945492SAndroid Build Coastguard Worker #include <stdint.h>
31*c9945492SAndroid Build Coastguard Worker
32*c9945492SAndroid Build Coastguard Worker /*
33*c9945492SAndroid Build Coastguard Worker * Fused multiply-add: Compute x * y + z with a single rounding error.
34*c9945492SAndroid Build Coastguard Worker *
35*c9945492SAndroid Build Coastguard Worker * A double has more than twice as much precision than a float, so
36*c9945492SAndroid Build Coastguard Worker * direct double-precision arithmetic suffices, except where double
37*c9945492SAndroid Build Coastguard Worker * rounding occurs.
38*c9945492SAndroid Build Coastguard Worker */
fmaf(float x,float y,float z)39*c9945492SAndroid Build Coastguard Worker float fmaf(float x, float y, float z)
40*c9945492SAndroid Build Coastguard Worker {
41*c9945492SAndroid Build Coastguard Worker #pragma STDC FENV_ACCESS ON
42*c9945492SAndroid Build Coastguard Worker double xy, result;
43*c9945492SAndroid Build Coastguard Worker union {double f; uint64_t i;} u;
44*c9945492SAndroid Build Coastguard Worker int e;
45*c9945492SAndroid Build Coastguard Worker
46*c9945492SAndroid Build Coastguard Worker xy = (double)x * y;
47*c9945492SAndroid Build Coastguard Worker result = xy + z;
48*c9945492SAndroid Build Coastguard Worker u.f = result;
49*c9945492SAndroid Build Coastguard Worker e = u.i>>52 & 0x7ff;
50*c9945492SAndroid Build Coastguard Worker /* Common case: The double precision result is fine. */
51*c9945492SAndroid Build Coastguard Worker if ((u.i & 0x1fffffff) != 0x10000000 || /* not a halfway case */
52*c9945492SAndroid Build Coastguard Worker e == 0x7ff || /* NaN */
53*c9945492SAndroid Build Coastguard Worker (result - xy == z && result - z == xy) || /* exact */
54*c9945492SAndroid Build Coastguard Worker fegetround() != FE_TONEAREST) /* not round-to-nearest */
55*c9945492SAndroid Build Coastguard Worker {
56*c9945492SAndroid Build Coastguard Worker /*
57*c9945492SAndroid Build Coastguard Worker underflow may not be raised correctly, example:
58*c9945492SAndroid Build Coastguard Worker fmaf(0x1p-120f, 0x1p-120f, 0x1p-149f)
59*c9945492SAndroid Build Coastguard Worker */
60*c9945492SAndroid Build Coastguard Worker #if defined(FE_INEXACT) && defined(FE_UNDERFLOW)
61*c9945492SAndroid Build Coastguard Worker if (e < 0x3ff-126 && e >= 0x3ff-149 && fetestexcept(FE_INEXACT)) {
62*c9945492SAndroid Build Coastguard Worker feclearexcept(FE_INEXACT);
63*c9945492SAndroid Build Coastguard Worker /* TODO: gcc and clang bug workaround */
64*c9945492SAndroid Build Coastguard Worker volatile float vz = z;
65*c9945492SAndroid Build Coastguard Worker result = xy + vz;
66*c9945492SAndroid Build Coastguard Worker if (fetestexcept(FE_INEXACT))
67*c9945492SAndroid Build Coastguard Worker feraiseexcept(FE_UNDERFLOW);
68*c9945492SAndroid Build Coastguard Worker else
69*c9945492SAndroid Build Coastguard Worker feraiseexcept(FE_INEXACT);
70*c9945492SAndroid Build Coastguard Worker }
71*c9945492SAndroid Build Coastguard Worker #endif
72*c9945492SAndroid Build Coastguard Worker z = result;
73*c9945492SAndroid Build Coastguard Worker return z;
74*c9945492SAndroid Build Coastguard Worker }
75*c9945492SAndroid Build Coastguard Worker
76*c9945492SAndroid Build Coastguard Worker /*
77*c9945492SAndroid Build Coastguard Worker * If result is inexact, and exactly halfway between two float values,
78*c9945492SAndroid Build Coastguard Worker * we need to adjust the low-order bit in the direction of the error.
79*c9945492SAndroid Build Coastguard Worker */
80*c9945492SAndroid Build Coastguard Worker double err;
81*c9945492SAndroid Build Coastguard Worker int neg = u.i >> 63;
82*c9945492SAndroid Build Coastguard Worker if (neg == (z > xy))
83*c9945492SAndroid Build Coastguard Worker err = xy - result + z;
84*c9945492SAndroid Build Coastguard Worker else
85*c9945492SAndroid Build Coastguard Worker err = z - result + xy;
86*c9945492SAndroid Build Coastguard Worker if (neg == (err < 0))
87*c9945492SAndroid Build Coastguard Worker u.i++;
88*c9945492SAndroid Build Coastguard Worker else
89*c9945492SAndroid Build Coastguard Worker u.i--;
90*c9945492SAndroid Build Coastguard Worker z = u.f;
91*c9945492SAndroid Build Coastguard Worker return z;
92*c9945492SAndroid Build Coastguard Worker }
93