xref: /aosp_15_r20/external/musl/src/math/fmaf.c (revision c9945492fdd68bbe62686c5b452b4dc1be3f8453)
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