summaryrefslogtreecommitdiff
path: root/gcc/real.c
diff options
context:
space:
mode:
authorsayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4>2003-04-23 02:46:03 +0000
committersayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4>2003-04-23 02:46:03 +0000
commit0a4f46e26c589fc77e7dcdbb7a3d510b6c0613c9 (patch)
treea4f65e0c74166fc582d3742c93aa64dd4ebcc3a1 /gcc/real.c
parenteb13b1821bc619f32ccc0292513b54b1cbc2d832 (diff)
downloadgcc-0a4f46e26c589fc77e7dcdbb7a3d510b6c0613c9.tar.gz
* real.c (do_add): Change to return a bool indicating that the
result of the operation may be inexact due to loss of precision. (do_multiply): Likewise. (do_divide): Likewise. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@65980 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/real.c')
-rw-r--r--gcc/real.c87
1 files changed, 52 insertions, 35 deletions
diff --git a/gcc/real.c b/gcc/real.c
index c79dd288b62..db658fdcb95 100644
--- a/gcc/real.c
+++ b/gcc/real.c
@@ -115,12 +115,12 @@ static bool div_significands PARAMS ((REAL_VALUE_TYPE *,
const REAL_VALUE_TYPE *));
static void normalize PARAMS ((REAL_VALUE_TYPE *));
-static void do_add PARAMS ((REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
+static bool do_add PARAMS ((REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
const REAL_VALUE_TYPE *, int));
-static void do_multiply PARAMS ((REAL_VALUE_TYPE *,
+static bool do_multiply PARAMS ((REAL_VALUE_TYPE *,
const REAL_VALUE_TYPE *,
const REAL_VALUE_TYPE *));
-static void do_divide PARAMS ((REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
+static bool do_divide PARAMS ((REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
const REAL_VALUE_TYPE *));
static int do_compare PARAMS ((const REAL_VALUE_TYPE *,
const REAL_VALUE_TYPE *, int));
@@ -563,9 +563,10 @@ normalize (r)
}
}
-/* Return R = A + (SUBTRACT_P ? -B : B). */
+/* Calculate R = A + (SUBTRACT_P ? -B : B). Return true if the
+ result may be inexact due to a loss of precision. */
-static void
+static bool
do_add (r, a, b, subtract_p)
REAL_VALUE_TYPE *r;
const REAL_VALUE_TYPE *a, *b;
@@ -584,7 +585,7 @@ do_add (r, a, b, subtract_p)
case CLASS2 (rvc_zero, rvc_zero):
/* -0 + -0 = -0, -0 - +0 = -0; all other cases yield +0. */
get_zero (r, sign & !subtract_p);
- return;
+ return false;
case CLASS2 (rvc_zero, rvc_normal):
case CLASS2 (rvc_zero, rvc_inf):
@@ -598,7 +599,7 @@ do_add (r, a, b, subtract_p)
/* R + Inf = Inf. */
*r = *b;
r->sign = sign ^ subtract_p;
- return;
+ return false;
case CLASS2 (rvc_normal, rvc_zero):
case CLASS2 (rvc_inf, rvc_zero):
@@ -610,7 +611,7 @@ do_add (r, a, b, subtract_p)
case CLASS2 (rvc_inf, rvc_normal):
/* Inf + R = Inf. */
*r = *a;
- return;
+ return false;
case CLASS2 (rvc_inf, rvc_inf):
if (subtract_p)
@@ -619,7 +620,7 @@ do_add (r, a, b, subtract_p)
else
/* Inf + Inf = Inf. */
*r = *a;
- return;
+ return false;
case CLASS2 (rvc_normal, rvc_normal):
break;
@@ -649,7 +650,7 @@ do_add (r, a, b, subtract_p)
{
*r = *a;
r->sign = sign;
- return;
+ return true;
}
inexact |= sticky_rshift_significand (&t, b, dexp);
@@ -680,7 +681,7 @@ do_add (r, a, b, subtract_p)
if (++exp > MAX_EXP)
{
get_inf (r, sign);
- return;
+ return true;
}
}
}
@@ -698,11 +699,13 @@ do_add (r, a, b, subtract_p)
r->sign = 0;
else
r->sig[0] |= inexact;
+
+ return inexact;
}
-/* Return R = A * B. */
+/* Calculate R = A * B. Return true if the result may be inexact. */
-static void
+static bool
do_multiply (r, a, b)
REAL_VALUE_TYPE *r;
const REAL_VALUE_TYPE *a, *b;
@@ -710,6 +713,7 @@ do_multiply (r, a, b)
REAL_VALUE_TYPE u, t, *rr;
unsigned int i, j, k;
int sign = a->sign ^ b->sign;
+ bool inexact = false;
switch (CLASS2 (a->class, b->class))
{
@@ -718,7 +722,7 @@ do_multiply (r, a, b)
case CLASS2 (rvc_normal, rvc_zero):
/* +-0 * ANY = 0 with appropriate sign. */
get_zero (r, sign);
- return;
+ return false;
case CLASS2 (rvc_zero, rvc_nan):
case CLASS2 (rvc_normal, rvc_nan):
@@ -727,7 +731,7 @@ do_multiply (r, a, b)
/* ANY * NaN = NaN. */
*r = *b;
r->sign = sign;
- return;
+ return false;
case CLASS2 (rvc_nan, rvc_zero):
case CLASS2 (rvc_nan, rvc_normal):
@@ -735,21 +739,20 @@ do_multiply (r, a, b)
/* NaN * ANY = NaN. */
*r = *a;
r->sign = sign;
- return;
+ return false;
case CLASS2 (rvc_zero, rvc_inf):
case CLASS2 (rvc_inf, rvc_zero):
/* 0 * Inf = NaN */
get_canonical_qnan (r, sign);
- return;
+ return false;
case CLASS2 (rvc_inf, rvc_inf):
case CLASS2 (rvc_normal, rvc_inf):
case CLASS2 (rvc_inf, rvc_normal):
/* Inf * Inf = Inf, R * Inf = Inf */
- overflow:
get_inf (r, sign);
- return;
+ return false;
case CLASS2 (rvc_normal, rvc_normal):
break;
@@ -799,10 +802,16 @@ do_multiply (r, a, b)
+ (b->exp - (1-j)*(HOST_BITS_PER_LONG/2)));
if (exp > MAX_EXP)
- goto overflow;
+ {
+ get_inf (r, sign);
+ return true;
+ }
if (exp < -MAX_EXP)
- /* Would underflow to zero, which we shouldn't bother adding. */
- continue;
+ {
+ /* Would underflow to zero, which we shouldn't bother adding. */
+ inexact = true;
+ continue;
+ }
u.class = rvc_normal;
u.sign = 0;
@@ -820,18 +829,20 @@ do_multiply (r, a, b)
}
normalize (&u);
- do_add (rr, rr, &u, 0);
+ inexact |= do_add (rr, rr, &u, 0);
}
}
rr->sign = sign;
if (rr != r)
*r = t;
+
+ return inexact;
}
-/* Return R = A / B. */
+/* Calculate R = A / B. Return true if the result may be inexact. */
-static void
+static bool
do_divide (r, a, b)
REAL_VALUE_TYPE *r;
const REAL_VALUE_TYPE *a, *b;
@@ -847,23 +858,22 @@ do_divide (r, a, b)
case CLASS2 (rvc_inf, rvc_inf):
/* Inf / Inf = NaN. */
get_canonical_qnan (r, sign);
- return;
+ return false;
case CLASS2 (rvc_zero, rvc_normal):
case CLASS2 (rvc_zero, rvc_inf):
/* 0 / ANY = 0. */
case CLASS2 (rvc_normal, rvc_inf):
/* R / Inf = 0. */
- underflow:
get_zero (r, sign);
- return;
+ return false;
case CLASS2 (rvc_normal, rvc_zero):
/* R / 0 = Inf. */
case CLASS2 (rvc_inf, rvc_zero):
/* Inf / 0 = Inf. */
get_inf (r, sign);
- return;
+ return false;
case CLASS2 (rvc_zero, rvc_nan):
case CLASS2 (rvc_normal, rvc_nan):
@@ -872,7 +882,7 @@ do_divide (r, a, b)
/* ANY / NaN = NaN. */
*r = *b;
r->sign = sign;
- return;
+ return false;
case CLASS2 (rvc_nan, rvc_zero):
case CLASS2 (rvc_nan, rvc_normal):
@@ -880,13 +890,12 @@ do_divide (r, a, b)
/* NaN / ANY = NaN. */
*r = *a;
r->sign = sign;
- return;
+ return false;
case CLASS2 (rvc_inf, rvc_normal):
/* Inf / R = Inf. */
- overflow:
get_inf (r, sign);
- return;
+ return false;
case CLASS2 (rvc_normal, rvc_normal):
break;
@@ -905,9 +914,15 @@ do_divide (r, a, b)
exp = a->exp - b->exp + 1;
if (exp > MAX_EXP)
- goto overflow;
+ {
+ get_inf (r, sign);
+ return true;
+ }
if (exp < -MAX_EXP)
- goto underflow;
+ {
+ get_zero (r, sign);
+ return true;
+ }
rr->exp = exp;
inexact = div_significands (rr, a, b);
@@ -918,6 +933,8 @@ do_divide (r, a, b)
if (rr != r)
*r = t;
+
+ return inexact;
}
/* Return a tri-state comparison of A vs B. Return NAN_RESULT if