1 /* Compute x * y + z as ternary operation.
2 Copyright (C) 2010-2012 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Jakub Jelinek <jakub@redhat.com>, 2010.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 #include "quadmath-imp.h"
26 # if defined HAVE_FEHOLDEXCEPT && defined HAVE_FESETROUND \
27 && defined HAVE_FEUPDATEENV && defined HAVE_FETESTEXCEPT \
28 && defined FE_TOWARDZERO && defined FE_INEXACT
33 /* This implementation uses rounding to odd to avoid problems with
34 double rounding. See a paper by Boldo and Melquiond:
35 http://www.lri.fr/~melquion/doc/08-tc.pdf */
38 fmaq (__float128 x
, __float128 y
, __float128 z
)
40 ieee854_float128 u
, v
, w
;
45 if (__builtin_expect (u
.ieee
.exponent
+ v
.ieee
.exponent
46 >= 0x7fff + IEEE854_FLOAT128_BIAS
48 || __builtin_expect (u
.ieee
.exponent
>= 0x7fff - FLT128_MANT_DIG
, 0)
49 || __builtin_expect (v
.ieee
.exponent
>= 0x7fff - FLT128_MANT_DIG
, 0)
50 || __builtin_expect (w
.ieee
.exponent
>= 0x7fff - FLT128_MANT_DIG
, 0)
51 || __builtin_expect (u
.ieee
.exponent
+ v
.ieee
.exponent
52 <= IEEE854_FLOAT128_BIAS
+ FLT128_MANT_DIG
, 0))
54 /* If z is Inf, but x and y are finite, the result should be
56 if (w
.ieee
.exponent
== 0x7fff
57 && u
.ieee
.exponent
!= 0x7fff
58 && v
.ieee
.exponent
!= 0x7fff)
60 /* If z is zero and x are y are nonzero, compute the result
61 as x * y to avoid the wrong sign of a zero result if x * y
63 if (z
== 0 && x
!= 0 && y
!= 0)
65 /* If x or y or z is Inf/NaN, or if fma will certainly overflow,
66 or if x * y is less than half of FLT128_DENORM_MIN,
67 compute as x * y + z. */
68 if (u
.ieee
.exponent
== 0x7fff
69 || v
.ieee
.exponent
== 0x7fff
70 || w
.ieee
.exponent
== 0x7fff
71 || u
.ieee
.exponent
+ v
.ieee
.exponent
72 > 0x7fff + IEEE854_FLOAT128_BIAS
73 || u
.ieee
.exponent
+ v
.ieee
.exponent
74 < IEEE854_FLOAT128_BIAS
- FLT128_MANT_DIG
- 2)
76 if (u
.ieee
.exponent
+ v
.ieee
.exponent
77 >= 0x7fff + IEEE854_FLOAT128_BIAS
- FLT128_MANT_DIG
)
79 /* Compute 1p-113 times smaller result and multiply
81 if (u
.ieee
.exponent
> v
.ieee
.exponent
)
82 u
.ieee
.exponent
-= FLT128_MANT_DIG
;
84 v
.ieee
.exponent
-= FLT128_MANT_DIG
;
85 /* If x + y exponent is very large and z exponent is very small,
86 it doesn't matter if we don't adjust it. */
87 if (w
.ieee
.exponent
> FLT128_MANT_DIG
)
88 w
.ieee
.exponent
-= FLT128_MANT_DIG
;
91 else if (w
.ieee
.exponent
>= 0x7fff - FLT128_MANT_DIG
)
94 If z exponent is very large and x and y exponents are
95 very small, it doesn't matter if we don't adjust it. */
96 if (u
.ieee
.exponent
> v
.ieee
.exponent
)
98 if (u
.ieee
.exponent
> FLT128_MANT_DIG
)
99 u
.ieee
.exponent
-= FLT128_MANT_DIG
;
101 else if (v
.ieee
.exponent
> FLT128_MANT_DIG
)
102 v
.ieee
.exponent
-= FLT128_MANT_DIG
;
103 w
.ieee
.exponent
-= FLT128_MANT_DIG
;
106 else if (u
.ieee
.exponent
>= 0x7fff - FLT128_MANT_DIG
)
108 u
.ieee
.exponent
-= FLT128_MANT_DIG
;
110 v
.ieee
.exponent
+= FLT128_MANT_DIG
;
114 else if (v
.ieee
.exponent
>= 0x7fff - FLT128_MANT_DIG
)
116 v
.ieee
.exponent
-= FLT128_MANT_DIG
;
118 u
.ieee
.exponent
+= FLT128_MANT_DIG
;
122 else /* if (u.ieee.exponent + v.ieee.exponent
123 <= IEEE854_FLOAT128_BIAS + FLT128_MANT_DIG) */
125 if (u
.ieee
.exponent
> v
.ieee
.exponent
)
126 u
.ieee
.exponent
+= 2 * FLT128_MANT_DIG
;
128 v
.ieee
.exponent
+= 2 * FLT128_MANT_DIG
;
129 if (w
.ieee
.exponent
<= 4 * FLT128_MANT_DIG
+ 4)
132 w
.ieee
.exponent
+= 2 * FLT128_MANT_DIG
;
137 /* Otherwise x * y should just affect inexact
145 /* Ensure correct sign of exact 0 + 0. */
146 if (__builtin_expect ((x
== 0 || y
== 0) && z
== 0, 0))
149 /* Multiplication m1 + m2 = x * y using Dekker's algorithm. */
150 #define C ((1LL << (FLT128_MANT_DIG + 1) / 2) + 1)
151 __float128 x1
= x
* C
;
152 __float128 y1
= y
* C
;
153 __float128 m1
= x
* y
;
156 __float128 x2
= x
- x1
;
157 __float128 y2
= y
- y1
;
158 __float128 m2
= (((x1
* y1
- m1
) + x1
* y2
) + x2
* y1
) + x2
* y2
;
160 /* Addition a1 + a2 = z + m1 using Knuth's algorithm. */
161 __float128 a1
= z
+ m1
;
162 __float128 t1
= a1
- z
;
163 __float128 t2
= a1
- t1
;
166 __float128 a2
= t1
+ t2
;
171 fesetround (FE_TOWARDZERO
);
173 /* Perform m2 + a2 addition with round to odd. */
176 if (__builtin_expect (adjust
== 0, 1))
179 if ((u
.ieee
.mant_low
& 1) == 0 && u
.ieee
.exponent
!= 0x7fff)
180 u
.ieee
.mant_low
|= fetestexcept (FE_INEXACT
) != 0;
183 /* Result is a1 + u.value. */
186 else if (__builtin_expect (adjust
> 0, 1))
189 if ((u
.ieee
.mant_low
& 1) == 0 && u
.ieee
.exponent
!= 0x7fff)
190 u
.ieee
.mant_low
|= fetestexcept (FE_INEXACT
) != 0;
193 /* Result is a1 + u.value, scaled up. */
194 return (a1
+ u
.value
) * 0x1p
113Q
;
199 if ((u
.ieee
.mant_low
& 1) == 0)
200 u
.ieee
.mant_low
|= fetestexcept (FE_INEXACT
) != 0;
202 v
.value
= a1
+ u
.value
;
203 /* Ensure the addition is not scheduled after fetestexcept call. */
204 asm volatile ("" : : "m" (v
.value
));
206 int j
= fetestexcept (FE_INEXACT
) != 0;
211 /* Ensure the following computations are performed in default rounding
212 mode instead of just reusing the round to zero computation. */
213 asm volatile ("" : "=m" (u
) : "m" (u
));
214 /* If a1 + u.value is exact, the only rounding happens during
217 return v
.value
* 0x1p
-226Q
;
218 /* If result rounded to zero is not subnormal, no double
219 rounding will occur. */
220 if (v
.ieee
.exponent
> 226)
221 return (a1
+ u
.value
) * 0x1p
-226Q
;
222 /* If v.value * 0x1p-226Q with round to zero is a subnormal above
223 or equal to FLT128_MIN / 2, then v.value * 0x1p-226Q shifts mantissa
224 down just by 1 bit, which means v.ieee.mant_low |= j would
225 change the round bit, not sticky or guard bit.
226 v.value * 0x1p-226Q never normalizes by shifting up,
227 so round bit plus sticky bit should be already enough
228 for proper rounding. */
229 if (v
.ieee
.exponent
== 226)
231 /* v.ieee.mant_low & 2 is LSB bit of the result before rounding,
232 v.ieee.mant_low & 1 is the round bit and j is our sticky
235 w
.ieee
.mant_low
= ((v
.ieee
.mant_low
& 3) << 1) | j
;
236 w
.ieee
.negative
= v
.ieee
.negative
;
237 v
.ieee
.mant_low
&= ~3U;
238 v
.value
*= 0x1p
-226L;
240 return v
.value
+ w
.value
;
242 v
.ieee
.mant_low
|= j
;
243 return v
.value
* 0x1p
-226Q
;