@@ -1,3 +1,9 @@
+2020-05-29 Patrick McGehearty <patrick.mcgehearty@oracle.com>
+
+ * libgcc2.c (__divdc3): Enhance accuracy of double precision
+ complex divide for input values with very large and very
+ small exponents.
+
2020-05-28 Dong JianQiang <dongjianqiang2@huawei.com>
PR gcov-profile/95332
@@ -2036,6 +2036,10 @@ CONCAT3(__mul,MODE,3) (MTYPE a, MTYPE b, MTYPE c, MTYPE d)
CTYPE
CONCAT3(__div,MODE,3) (MTYPE a, MTYPE b, MTYPE c, MTYPE d)
{
+#define RBIG ((DBL_MAX)/2.0)
+#define RMIN (DBL_MIN)
+#define RMIN2 (0x1.0p-512)
+#define RMINSCAL (0x1.0p+510)
MTYPE denom, ratio, x, y;
CTYPE res;
@@ -2043,19 +2047,71 @@ CONCAT3(__div,MODE,3) (MTYPE a, MTYPE b, MTYPE c, MTYPE d)
the division. But that would mean starting to link libgcc against
libm. We could implement something akin to ldexp/frexp as gcc builtins
fairly easily... */
+ /*
+ Scaling by max(c,d) shifts a division and avoids a multiplication
+ reducing round-off errors by a modest amount (average of a half-bit)
+ */
if (FABS (c) < FABS (d))
{
+ /* prevent overflow when arguments are near max representable */
+ if ((FABS (d) >= RBIG) || (FABS (a) >= RBIG) || (FABS (b) >= RBIG) )
+ {
+ a = a * 0.5;
+ b = b * 0.5;
+ c = c * 0.5;
+ d = d * 0.5;
+ }
+ /* avoid overflow/underflow issues when c and d are small */
+ else if (FABS (d) < RMIN2)
+ {
+ a = a * RMINSCAL;
+ b = b * RMINSCAL;
+ c = c * RMINSCAL;
+ d = d * RMINSCAL;
+ }
ratio = c / d;
denom = (c * ratio) + d;
- x = ((a * ratio) + b) / denom;
- y = ((b * ratio) - a) / denom;
+ if ( FABS (ratio) > RMIN )
+ {
+ x = ((a * ratio) + b) / denom;
+ y = ((b * ratio) - a) / denom;
+ }
+ else
+ {
+ x = ((c * (a / d)) + b) / denom;
+ y = ((c * (b / d)) - a) / denom;
+ }
}
else
{
+ /* prevent overflow when arguments are near max representable */
+ if ((FABS(c) >= RBIG) || (FABS(a) >= RBIG) || (FABS(b) >= RBIG) )
+ {
+ a = a * 0.5;
+ b = b * 0.5;
+ c = c * 0.5;
+ d = d * 0.5;
+ }
+ /* avoid overflow issues when c and d are small */
+ else if (FABS(c) < RMIN2)
+ {
+ a = a * RMINSCAL;
+ b = b * RMINSCAL;
+ c = c * RMINSCAL;
+ d = d * RMINSCAL;
+ }
ratio = d / c;
denom = (d * ratio) + c;
- x = ((b * ratio) + a) / denom;
- y = (b - (a * ratio)) / denom;
+ if ( FABS (ratio) > RMIN )
+ {
+ x = (a + (b * ratio)) / denom;
+ y = (b - (a * ratio)) / denom;
+ }
+ else
+ {
+ x = (a + (d * (b / c))) / denom;
+ y = (b - (d * (a / c))) / denom;
+ }
}
/* Recover infinities and zeros that computed as NaN+iNaN; the only cases