summaryrefslogtreecommitdiff
path: root/mpf
diff options
context:
space:
mode:
authorMarco Bodrato <bodrato@mail.dm.unipi.it>2014-05-31 08:44:13 +0200
committerMarco Bodrato <bodrato@mail.dm.unipi.it>2014-05-31 08:44:13 +0200
commit90f69076b3af550c11d8997967c0c56b6b618972 (patch)
treeb442f67a00ebc2705723341aa1a1102878b1f641 /mpf
parent36403aac8a316e1c41133ac0d43dff1b760e8121 (diff)
downloadgmp-90f69076b3af550c11d8997967c0c56b6b618972.tar.gz
mpf/ui_sub.c: Remove buggy code, use a wrapper to mpf_sub.
Diffstat (limited to 'mpf')
-rw-r--r--mpf/ui_sub.c262
1 files changed, 104 insertions, 158 deletions
diff --git a/mpf/ui_sub.c b/mpf/ui_sub.c
index 660ede774..710502466 100644
--- a/mpf/ui_sub.c
+++ b/mpf/ui_sub.c
@@ -1,6 +1,6 @@
/* mpf_ui_sub -- Subtract a float from an unsigned long int.
-Copyright 1993-1996, 2001, 2002, 2005 Free Software Foundation, Inc.
+Copyright 1993-1996, 2001, 2002, 2005, 2014 Free Software Foundation, Inc.
This file is part of the GNU MP Library.
@@ -34,6 +34,23 @@ see https://www.gnu.org/licenses/. */
void
mpf_ui_sub (mpf_ptr r, unsigned long int u, mpf_srcptr v)
{
+#if 1
+ __mpf_struct uu;
+ mp_limb_t ul;
+
+ if (u == 0)
+ {
+ mpf_neg (r, v);
+ return;
+ }
+
+ ul = u;
+ uu._mp_size = 1;
+ uu._mp_d = &ul;
+ uu._mp_exp = 1;
+ mpf_sub (r, &uu, v);
+
+#else
mp_srcptr up, vp;
mp_ptr rp, tp;
mp_size_t usize, vsize, rsize;
@@ -69,89 +86,64 @@ mpf_ui_sub (mpf_ptr r, unsigned long int u, mpf_srcptr v)
return;
}
- TMP_MARK;
-
/* Signs are now known to be the same. */
-
+ ASSERT (vsize > 0);
ulimb = u;
/* Make U be the operand with the largest exponent. */
- if (1 < v->_mp_exp)
+ negate = 1 < v->_mp_exp;
+ prec = r->_mp_prec + negate;
+ rp = r->_mp_d;
+ if (negate)
{
- negate = 1;
- usize = ABS (vsize);
+ usize = vsize;
vsize = 1;
up = v->_mp_d;
vp = &ulimb;
- rp = r->_mp_d;
- prec = r->_mp_prec + 1;
uexp = v->_mp_exp;
ediff = uexp - 1;
+
+ /* If U extends beyond PREC, ignore the part that does. */
+ if (usize > prec)
+ {
+ up += usize - prec;
+ usize = prec;
+ }
+ ASSERT (ediff > 0);
}
else
{
- negate = 0;
- usize = 1;
- vsize = ABS (vsize);
- up = &ulimb;
vp = v->_mp_d;
- rp = r->_mp_d;
- prec = r->_mp_prec;
- uexp = 1;
ediff = 1 - v->_mp_exp;
- }
-
/* Ignore leading limbs in U and V that are equal. Doing
this helps increase the precision of the result. */
- if (ediff == 0)
- {
- /* This loop normally exits immediately. Optimize for that. */
- for (;;)
+ if (ediff == 0 && ulimb == vp[vsize - 1])
{
- usize--;
+ usize = 0;
vsize--;
- if (up[usize] != vp[vsize])
- break;
- uexp--;
- if (usize == 0)
- goto Lu0;
- if (vsize == 0)
- goto Lv0;
+ uexp = 0;
+ /* Note that V might now have leading zero limbs.
+ In that case we have to adjust uexp. */
+ for (;;)
+ {
+ if (vsize == 0) {
+ rsize = 0;
+ uexp = 0;
+ goto done;
+ }
+ if ( vp[vsize - 1] != 0)
+ break;
+ vsize--, uexp--;
+ }
}
- usize++;
- vsize++;
- /* Note that either operand (but not both operands) might now have
- leading zero limbs. It matters only that U is unnormalized if
- vsize is now zero, and vice versa. And it is only in that case
- that we have to adjust uexp. */
- if (vsize == 0)
- Lv0:
- while (usize != 0 && up[usize - 1] == 0)
- usize--, uexp--;
- if (usize == 0)
- Lu0:
- while (vsize != 0 && vp[vsize - 1] == 0)
- vsize--, uexp--;
- }
-
- /* If U extends beyond PREC, ignore the part that does. */
- if (usize > prec)
- {
- up += usize - prec;
- usize = prec;
- }
-
- /* If V extends beyond PREC, ignore the part that does.
- Note that this may make vsize negative. */
- if (vsize + ediff > prec)
- {
- vp += vsize + ediff - prec;
- vsize = prec - ediff;
+ else
+ {
+ usize = 1;
+ uexp = 1;
+ up = &ulimb;
+ }
+ ASSERT (usize <= prec);
}
- /* Allocate temp space for the result. Allocate
- just vsize + ediff later??? */
- tp = TMP_ALLOC_LIMBS (prec);
-
if (ediff >= prec)
{
/* V completely cancelled. */
@@ -161,19 +153,28 @@ mpf_ui_sub (mpf_ptr r, unsigned long int u, mpf_srcptr v)
}
else
{
+ /* If V extends beyond PREC, ignore the part that does.
+ Note that this can make vsize neither zero nor negative. */
+ if (vsize + ediff > prec)
+ {
+ vp += vsize + ediff - prec;
+ vsize = prec - ediff;
+ }
+
/* Locate the least significant non-zero limb in (the needed
parts of) U and V, to simplify the code below. */
+ ASSERT (vsize > 0);
for (;;)
{
+ if (vp[0] != 0)
+ break;
+ vp++, vsize--;
if (vsize == 0)
{
MPN_COPY (rp, up, usize);
rsize = usize;
goto done;
}
- if (vp[0] != 0)
- break;
- vp++, vsize--;
}
for (;;)
{
@@ -189,6 +190,11 @@ mpf_ui_sub (mpf_ptr r, unsigned long int u, mpf_srcptr v)
up++, usize--;
}
+ ASSERT (usize > 0 && vsize > 0);
+ TMP_MARK;
+
+ tp = TMP_ALLOC_LIMBS (prec);
+
/* uuuu | uuuu | uuuu | uuuu | uuuu */
/* vvvvvvv | vv | vvvvv | v | vv */
@@ -197,112 +203,53 @@ mpf_ui_sub (mpf_ptr r, unsigned long int u, mpf_srcptr v)
/* U and V partially overlaps. */
if (ediff == 0)
{
- /* Have to compare the leading limbs of u and v
- to determine whether to compute u - v or v - u. */
- if (usize > vsize)
+ ASSERT (usize == 1 && vsize >= 1 && ulimb == *up); /* usize is 1>ediff, vsize >= 1 */
+ if (1 < vsize)
{
- /* uuuu */
- /* vv */
- int cmp;
- cmp = mpn_cmp (up + usize - vsize, vp, vsize);
- if (cmp >= 0)
- {
- mp_size_t size;
- size = usize - vsize;
- MPN_COPY (tp, up, size);
- mpn_sub_n (tp + size, up + size, vp, vsize);
- rsize = usize;
- }
- else
- {
- /* vv */ /* Swap U and V. */
- /* uuuu */
- mp_size_t size, i;
- size = usize - vsize;
- tp[0] = -up[0] & GMP_NUMB_MASK;
- for (i = 1; i < size; i++)
- tp[i] = ~up[i] & GMP_NUMB_MASK;
- mpn_sub_n (tp + size, vp, up + size, vsize);
- mpn_sub_1 (tp + size, tp + size, vsize, (mp_limb_t) 1);
- negate ^= 1;
- rsize = usize;
- }
- }
- else if (usize < vsize)
- {
- /* uuuu */
+ /* u */
/* vvvvvvv */
- int cmp;
- cmp = mpn_cmp (up, vp + vsize - usize, usize);
- if (cmp > 0)
+ rsize = vsize;
+ vsize -= 1;
+ /* mpn_cmp (up, vp + vsize - usize, usize) > 0 */
+ if (ulimb > vp[vsize])
{
- mp_size_t size, i;
- size = vsize - usize;
- tp[0] = -vp[0] & GMP_NUMB_MASK;
- for (i = 1; i < size; i++)
- tp[i] = ~vp[i] & GMP_NUMB_MASK;
- mpn_sub_n (tp + size, up, vp + size, usize);
- mpn_sub_1 (tp + size, tp + size, usize, (mp_limb_t) 1);
- rsize = vsize;
+ tp[vsize] = ulimb - vp[vsize] - 1;
+ ASSERT_CARRY (mpn_neg (tp, vp, vsize));
}
else
{
/* vvvvvvv */ /* Swap U and V. */
- /* uuuu */
- /* This is the only place we can get 0.0. */
- mp_size_t size;
- size = vsize - usize;
- MPN_COPY (tp, vp, size);
- mpn_sub_n (tp + size, vp + size, up, usize);
- negate ^= 1;
- rsize = vsize;
+ /* u */
+ MPN_COPY (tp, vp, vsize);
+ tp[vsize] = vp[vsize] - ulimb;
+ negate = 1;
}
}
- else
+ else /* vsize == usize == 1 */
{
- /* uuuu */
- /* vvvv */
- int cmp;
- cmp = mpn_cmp (up, vp + vsize - usize, usize);
- if (cmp > 0)
- {
- mpn_sub_n (tp, up, vp, usize);
- rsize = usize;
- }
- else
- {
- mpn_sub_n (tp, vp, up, usize);
- negate ^= 1;
- rsize = usize;
- /* can give zero */
- }
+ /* u */
+ /* v */
+ rsize = 1;
+ negate = ulimb < vp[0];
+ tp[0] = negate ? vp[0] - ulimb: ulimb - vp[0];
}
}
else
{
- if (vsize + ediff <= usize)
+ ASSERT (vsize + ediff <= usize);
+ ASSERT (vsize == 1 && usize >= 2 && ulimb == *vp);
{
/* uuuu */
/* v */
mp_size_t size;
- size = usize - ediff - vsize;
+ size = usize - ediff - 1;
MPN_COPY (tp, up, size);
- mpn_sub (tp + size, up + size, usize - size, vp, vsize);
+ ASSERT_NOCARRY (mpn_sub_1 (tp + size, up + size, usize - size, ulimb));
rsize = usize;
}
- else
- {
- /* uuuu */
- /* vvvvv */
- mp_size_t size, i;
- size = vsize + ediff - usize;
- tp[0] = -vp[0] & GMP_NUMB_MASK;
- for (i = 1; i < size; i++)
- tp[i] = ~vp[i] & GMP_NUMB_MASK;
- mpn_sub (tp + size, up, usize, vp + size, usize - ediff);
- mpn_sub_1 (tp + size, tp + size, usize, (mp_limb_t) 1);
- rsize = vsize + ediff;
- }
+ /* Other cases are not possible */
+ /* uuuu */
+ /* vvvvv */
}
}
else
@@ -310,14 +257,12 @@ mpf_ui_sub (mpf_ptr r, unsigned long int u, mpf_srcptr v)
/* uuuu */
/* vv */
mp_size_t size, i;
- size = vsize + ediff - usize;
- tp[0] = -vp[0] & GMP_NUMB_MASK;
- for (i = 1; i < vsize; i++)
- tp[i] = ~vp[i] & GMP_NUMB_MASK;
+ ASSERT_CARRY (mpn_neg (tp, vp, vsize));
+ rsize = vsize + ediff;
+ size = rsize - usize;
for (i = vsize; i < size; i++)
tp[i] = GMP_NUMB_MAX;
- mpn_sub_1 (tp + size, up, usize, (mp_limb_t) 1);
- rsize = size + usize;
+ ASSERT_NOCARRY (mpn_sub_1 (tp + size, up, usize, CNST_LIMB (1)));
}
/* Full normalize. Optimize later. */
@@ -327,10 +272,11 @@ mpf_ui_sub (mpf_ptr r, unsigned long int u, mpf_srcptr v)
uexp--;
}
MPN_COPY (rp, tp, rsize);
+ TMP_FREE;
}
done:
r->_mp_size = negate ? -rsize : rsize;
r->_mp_exp = uexp;
- TMP_FREE;
+#endif
}