1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2005-2011 David Schultz <das@FreeBSD.ORG> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <fenv.h> 30 #include <float.h> /* Needed for FLT_MANT_DIG. */ 31 32 #include "math.h" 33 #include "math_private.h" 34 35 #pragma STDC FENV_ACCESS ON 36 37 #ifdef USE_BUILTIN_FMAF 38 float 39 #ifdef _RENAME_FMAF 40 fmaf_sw 41 #else 42 fmaf 43 #endif 44 (float x, float y, float z) 45 { 46 return (__builtin_fmaf(x, y, z)); 47 } 48 #else 49 50 #define _CC (0x1p12F + 1) /* Needed by _SLOW2SUM() and _MUL() below */ 51 52 /* 53 * A struct dd represents a floating-point number with twice the precision 54 * of a float. We maintain the invariant that "hi" stores the 24 high-order 55 * bits of the result. 56 */ 57 struct dd { 58 float hi; 59 float lo; 60 }; 61 62 /* 63 * Compute a+b exactly, returning the exact result in a struct dd. We assume 64 * that both a and b are finite, but make no assumptions about their relative 65 * magnitudes. 66 */ 67 static inline struct dd 68 dd_add(float a, float b) 69 { 70 struct dd ret; 71 _SLOW2SUM(a, b, ret.hi, ret.lo); 72 return (ret); 73 } 74 75 /* 76 * Compute a+b, with a small tweak: The least significant bit of the 77 * result is adjusted into a sticky bit summarizing all the bits that 78 * were lost to rounding. This adjustment negates the effects of double 79 * rounding when the result is added to another number with a higher 80 * exponent. For an explanation of round and sticky bits, see any reference 81 * on FPU design, e.g., 82 * 83 * J. Coonen. An Implementation Guide to a Proposed Standard for 84 * Floating-Point Arithmetic. Computer, vol. 13, no. 1, Jan 1980. 85 */ 86 static inline float 87 add_adjusted(float a, float b) 88 { 89 struct dd sum; 90 uint32_t hibits, lobits; 91 92 sum = dd_add(a, b); 93 if (sum.lo != 0) { 94 GET_FLOAT_WORD(hibits, sum.hi); 95 if ((hibits & 1) == 0) { 96 /* hibits += (int)copysignf(1.0f, sum.hi * sum.lo); */ 97 GET_FLOAT_WORD(lobits, sum.lo); 98 hibits += 1 - ((hibits ^ lobits) >> 30); 99 SET_FLOAT_WORD(sum.hi, hibits); 100 } 101 } 102 return (sum.hi); 103 } 104 105 /* 106 * Compute ldexp(a+b, scale) with a single rounding error. It is assumed 107 * that the result will be subnormal, and care is taken to ensure that 108 * double rounding does not occur. 109 */ 110 111 static inline float 112 add_and_denormalize(float a, float b, int scale) 113 { 114 struct dd sum; 115 uint32_t hibits, lobits; 116 int bits_lost; 117 118 sum = dd_add(a, b); 119 120 /* 121 * If we are losing at least two bits of accuracy to denormalization, 122 * then the first lost bit becomes a round bit, and we adjust the 123 * lowest bit of sum.hi to make it a sticky bit summarizing all the 124 * bits in sum.lo. With the sticky bit adjusted, the hardware will 125 * break any ties in the correct direction. 126 * 127 * If we are losing only one bit to denormalization, however, we must 128 * break the ties manually. 129 */ 130 if (sum.lo != 0) { 131 GET_FLOAT_WORD(hibits, sum.hi); 132 bits_lost = -((int)(hibits >> 24) & 0x7f) - scale + 1; 133 if ((bits_lost != 1) ^ (int)(hibits & 1)) { 134 /* hibits += (int)copysign(1.0, sum.hi * sum.lo) */ 135 GET_FLOAT_WORD(lobits, sum.lo); 136 hibits += 1 - (((hibits ^ lobits) >> 30) & 2); 137 SET_FLOAT_WORD(sum.hi, hibits); 138 } 139 } 140 return (ldexpf(sum.hi, scale)); 141 } 142 143 /* 144 * Compute a*b exactly, returning the exact result in a struct dd. We assume 145 * that both a and b are normalized, so no underflow or overflow will occur. 146 * The current rounding mode must be round-to-nearest. 147 */ 148 static inline struct dd 149 dd_mul(float a, float b) 150 { 151 struct dd ret; 152 _MUL(a, b, ret.hi, ret.lo); 153 return (ret); 154 } 155 156 #ifdef _RENAME_FMAF 157 float fmaf_sw(float, float, float); 158 #endif 159 160 /* 161 * Fused multiply-add: Compute x * y + z with a single rounding error. 162 * 163 * We use scaling to avoid overflow/underflow, along with the 164 * canonical precision-doubling technique adapted from: 165 * 166 * Dekker, T. A Floating-Point Technique for Extending the 167 * Available Precision. Numer. Math. 18, 224-242 (1971). 168 * 169 * This algorithm is sensitive to the rounding precision. FPUs such 170 * as the i387 must be set in double-precision mode if variables are 171 * to be stored in FP registers in order to avoid incorrect results. 172 * This is the default on FreeBSD, but not on many other systems. 173 * 174 * Hardware instructions should be used on architectures that support it, 175 * since this implementation will likely be several times slower. 176 */ 177 float 178 #ifdef _RENAME_FMAF 179 fmaf_sw 180 #else 181 fmaf 182 #endif 183 (float x, float y, float z) 184 { 185 float xs, ys, zs, adj; 186 struct dd xy, r; 187 int oround; 188 int ex, ey, ez; 189 int spread; 190 191 /* 192 * Handle special cases. The order of operations and the particular 193 * return values here are crucial in handling special cases involving 194 * infinities, NaNs, overflows, and signed zeroes correctly. 195 */ 196 if (x == 0 || y == 0) 197 return (x * y + z); 198 if (z == 0) 199 return (x * y); 200 if (!isfinite(x) || !isfinite(y)) 201 return (x * y + z); 202 if (!isfinite(z)) 203 return (z); 204 205 xs = frexpf(x, &ex); 206 ys = frexpf(y, &ey); 207 zs = frexpf(z, &ez); 208 oround = fegetround(); 209 spread = ex + ey - ez; 210 211 /* 212 * If x * y and z are many orders of magnitude apart, the scaling 213 * will overflow, so we handle these cases specially. Rounding 214 * modes other than FE_TONEAREST are painful. 215 */ 216 if (spread < -FLT_MANT_DIG) { 217 feraiseexcept(FE_INEXACT); 218 if (!isnormal(z)) 219 feraiseexcept(FE_UNDERFLOW); 220 switch (oround) { 221 case FE_TONEAREST: 222 return (z); 223 case FE_TOWARDZERO: 224 if ((x > 0) ^ (y < 0) ^ (z < 0)) 225 return (z); 226 else 227 return (nextafterf(z, 0)); 228 case FE_DOWNWARD: 229 if ((x > 0) ^ (y < 0)) 230 return (z); 231 else 232 return (nextafterf(z, -INFINITY)); 233 default: /* FE_UPWARD */ 234 if ((x > 0) ^ (y < 0)) 235 return (nextafterf(z, INFINITY)); 236 else 237 return (z); 238 } 239 } 240 if (spread <= FLT_MANT_DIG * 2) 241 zs = ldexpf(zs, -spread); 242 else 243 zs = copysignf(FLT_MIN, zs); 244 245 fesetround(FE_TONEAREST); 246 /* work around clang issue #8472 */ 247 volatile float vxs = xs; 248 249 /* 250 * Basic approach for round-to-nearest: 251 * 252 * (xy.hi, xy.lo) = x * y (exact) 253 * (r.hi, r.lo) = xy.hi + z (exact) 254 * adj = xy.lo + r.lo (inexact; low bit is sticky) 255 * result = r.hi + adj (correctly rounded) 256 */ 257 xy = dd_mul(vxs, ys); 258 r = dd_add(xy.hi, zs); 259 260 spread = ex + ey; 261 262 if (r.hi == 0 && xy.lo == 0) { 263 /* 264 * When the addends cancel to 0, ensure that the result has 265 * the correct sign. 266 */ 267 fesetround(oround); 268 volatile float vzs = zs; /* XXX gcc CSE bug workaround */ 269 return (xy.hi + vzs); 270 } 271 272 if (oround != FE_TONEAREST) { 273 /* 274 * There is no need to worry about double rounding in directed 275 * rounding modes. 276 */ 277 fesetround(oround); 278 /* work around clang issue #8472 */ 279 volatile float vrlo = r.lo; 280 adj = vrlo + xy.lo; 281 return (ldexpf(r.hi + adj, spread)); 282 } 283 284 adj = add_adjusted(r.lo, xy.lo); 285 286 if (spread + ilogbf(r.hi) > -127) 287 return (ldexpf(r.hi + adj, spread)); 288 else 289 return (add_and_denormalize(r.hi, adj, spread)); 290 } 291 #endif /* !USE_BUILTIN_FMAF */ 292