summaryrefslogtreecommitdiffstats
path: root/gnu/lib/libgmp/mpn_sub.c
diff options
context:
space:
mode:
authormarkm <markm@FreeBSD.org>1995-11-12 14:40:41 +0000
committermarkm <markm@FreeBSD.org>1995-11-12 14:40:41 +0000
commitd938bb78837327b46dc34873a6eb60c002605808 (patch)
treed720c213b0c2f268c17d14276e809e876bd37dc8 /gnu/lib/libgmp/mpn_sub.c
parent7e662b2efdf7b11bed05bdd944746d7b7d0e56af (diff)
downloadFreeBSD-src-d938bb78837327b46dc34873a6eb60c002605808.zip
FreeBSD-src-d938bb78837327b46dc34873a6eb60c002605808.tar.gz
GNU MP (Multiprecision) library. This is needed by secure RPC (being
done by Bill Paul) and various other BSD programs. Obtained from:FSF
Diffstat (limited to 'gnu/lib/libgmp/mpn_sub.c')
-rw-r--r--gnu/lib/libgmp/mpn_sub.c162
1 files changed, 162 insertions, 0 deletions
diff --git a/gnu/lib/libgmp/mpn_sub.c b/gnu/lib/libgmp/mpn_sub.c
new file mode 100644
index 0000000..3ba8afd
--- /dev/null
+++ b/gnu/lib/libgmp/mpn_sub.c
@@ -0,0 +1,162 @@
+/* mpn_sub -- Subtract two low-level natural-number integers.
+
+Copyright (C) 1991 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU MP Library; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+/* Subtract SUB_PTR/SUB_SIZE from MIN_PTR/MIN_SIZE and store the
+ result (MIN_SIZE words) at DIF_PTR.
+
+ Return 1 if min < sub (result is negative). Otherwise, return the
+ negative difference between the number of words in dif and min.
+ (I.e. return 0 if the result has MIN_SIZE words, -1 if it has
+ MIN_SIZE - 1 words, etc.)
+
+ Argument constraint: MIN_SIZE >= SUB_SIZE.
+
+ The size of DIF can be calculated as MIN_SIZE + the return value. */
+
+mp_size
+#ifdef __STDC__
+mpn_sub (mp_ptr dif_ptr,
+ mp_srcptr min_ptr, mp_size min_size,
+ mp_srcptr sub_ptr, mp_size sub_size)
+#else
+mpn_sub (dif_ptr, min_ptr, min_size, sub_ptr, sub_size)
+ mp_ptr dif_ptr;
+ mp_srcptr min_ptr;
+ mp_size min_size;
+ mp_srcptr sub_ptr;
+ mp_size sub_size;
+#endif
+{
+ mp_limb m, s, dif;
+ mp_size j;
+
+ /* The loop counter and index J goes from some negative value to zero.
+ This way the loops are faster. Need to offset the base pointers
+ to take care of the negative indices. */
+
+ j = -sub_size;
+ if (j == 0)
+ goto sub_finished;
+
+ min_ptr -= j;
+ sub_ptr -= j;
+ dif_ptr -= j;
+
+ /* There are two do-loops, marked NON-CARRY LOOP and CARRY LOOP that
+ jump between each other. The first loop is for when the previous
+ subtraction didn't produce a carry-out; the second is for the
+ complementary case. */
+
+ /* NON-CARRY LOOP */
+ do
+ {
+ m = min_ptr[j];
+ s = sub_ptr[j];
+ dif = m - s;
+ dif_ptr[j] = dif;
+ if (dif > m)
+ goto cy_loop;
+ ncy_loop:
+ j++;
+ }
+ while (j < 0);
+
+ /* We have exhausted SUB, with no carry out. Copy remaining part of
+ MIN to DIF. */
+
+ sub_finished:
+ j = sub_size - min_size;
+
+ /* If there's no difference between the length of the operands, the
+ last words might have become zero, and re-normalization is needed. */
+ if (j == 0)
+ goto normalize;
+
+ min_ptr -= j;
+ dif_ptr -= j;
+
+ goto copy;
+
+ /* CARRY LOOP */
+ do
+ {
+ m = min_ptr[j];
+ s = sub_ptr[j];
+ dif = m - s - 1;
+ dif_ptr[j] = dif;
+ if (dif < m)
+ goto ncy_loop;
+ cy_loop:
+ j++;
+ }
+ while (j < 0);
+
+ /* We have exhausted SUB, but need to propagate carry. */
+
+ j = sub_size - min_size;
+ if (j == 0)
+ return 1; /* min < sub. Flag it to the caller */
+
+ min_ptr -= j;
+ dif_ptr -= j;
+
+ /* Propagate carry. Sooner or later the carry will cancel with a
+ non-zero word, because the minuend is normalized. Considering this,
+ there's no need to test the index J. */
+ for (;;)
+ {
+ m = min_ptr[j];
+ dif = m - 1;
+ dif_ptr[j] = dif;
+ j++;
+ if (dif < m)
+ break;
+ }
+
+ if (j == 0)
+ goto normalize;
+
+ copy:
+ /* Don't copy the remaining words of MIN to DIF if MIN_PTR and DIF_PTR
+ are equal. It would just be a no-op copying. Return 0, as the length
+ of the result equals that of the minuend. */
+ if (dif_ptr == min_ptr)
+ return 0;
+
+ do
+ {
+ dif_ptr[j] = min_ptr[j];
+ j++;
+ }
+ while (j < 0);
+ return 0;
+
+ normalize:
+ for (j = -1; j >= -min_size; j--)
+ {
+ if (dif_ptr[j] != 0)
+ return j + 1;
+ }
+
+ return -min_size;
+}
OpenPOWER on IntegriCloud