From 38ec4b785188bcf289411c2b4e9e487e95558dd9 Mon Sep 17 00:00:00 2001 From: steve Date: Tue, 17 Feb 2004 06:52:55 +0000 Subject: [PATCH] Support unsigned divide of huge numbers. --- verinum.cc | 96 +++++++++++++++++++++++++++++++++++++++++++++++------- verinum.h | 8 ++++- 2 files changed, 91 insertions(+), 13 deletions(-) diff --git a/verinum.cc b/verinum.cc index 8f0e86a29..2c0865fcb 100644 --- a/verinum.cc +++ b/verinum.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: verinum.cc,v 1.41 2003/10/26 04:54:56 steve Exp $" +#ident "$Id: verinum.cc,v 1.42 2004/02/17 06:52:55 steve Exp $" #endif # include "config.h" @@ -467,12 +467,16 @@ verinum::V operator <= (const verinum&left, const verinum&right) if (right[idx-1] != verinum::V0) return verinum::V1; } + idx = right.len(); + if (left.len() < idx) idx = left.len(); + while (idx > 0) { if (left[idx-1] == verinum::Vx) return verinum::Vx; if (left[idx-1] == verinum::Vz) return verinum::Vx; if (right[idx-1] == verinum::Vx) return verinum::Vx; if (right[idx-1] == verinum::Vz) return verinum::Vx; if (left[idx-1] > right[idx-1]) return verinum::V0; + if (left[idx-1] < right[idx-1]) return verinum::V1; idx -= 1; } @@ -694,6 +698,68 @@ verinum operator * (const verinum&left, const verinum&right) return trim_vnum(result); } +verinum operator << (const verinum&that, unsigned shift) +{ + verinum result(verinum::V0, that.len() + shift, that.has_len()); + + for (unsigned idx = 0 ; idx < that.len() ; idx += 1) + result.set(idx+shift, that.get(idx)); + + return result; +} + +verinum operator >> (const verinum&that, unsigned shift) +{ + if (shift >= that.len()) { + if (that.has_sign()) { + verinum result (that.get(that.len()-1), 1); + result.has_sign(true); + return result; + } else { + verinum result(verinum::V0, 1); + return result; + } + } + + verinum result(that.has_sign()? that.get(that.len()-1) : verinum::V0, + that.len() - shift, that.has_len()); + + for (unsigned idx = shift ; idx < that.len() ; idx += 1) + result.set(idx-shift, that.get(idx)); + + return result; +} + +static verinum unsigned_divide(verinum num, verinum den) +{ + unsigned nwid = num.len(); + while (nwid > 0 && (num.get(nwid-1) == verinum::V0)) + nwid -= 1; + + unsigned dwid = den.len(); + while (dwid > 0 && (den.get(dwid-1) == verinum::V0)) + dwid -= 1; + + if (dwid > nwid) + return verinum(verinum::V0, 1); + + den = den << (nwid-dwid); + + unsigned idx = nwid - dwid + 1; + verinum result (verinum::V0, idx); + while (idx > 0) { + if (den <= num) { + verinum dif = num - den; + num = dif; + result.set(idx-1, verinum::V1); + } + den = den >> 1; + idx -= 1; + } + + return result; +} + /* * This operator divides the left number by the right number. If * either value is signed, the result is signed. If both values have a @@ -716,7 +782,7 @@ verinum operator / (const verinum&left, const verinum&right) /* If the right expression is a zero value, then the result is filled with 'bx bits. */ - if (right.as_ulong() == 0) { + if (right.is_zero()) { verinum result (verinum::Vx, use_len, has_len_flag); result.has_sign(left.has_sign() || right.has_sign()); return result; @@ -743,16 +809,19 @@ verinum operator / (const verinum&left, const verinum&right) } else { - /* XXXX FIXME XXXX Use native unsigned division to do - the work. This does not work if the result is too - large for the native integer. */ - assert(use_len <= 8*sizeof(unsigned long)); - unsigned long l = left.as_ulong(); - unsigned long r = right.as_ulong(); - unsigned long v = l / r; - for (unsigned idx = 0 ; idx < use_len ; idx += 1) { - result.set(idx, (v & 1)? verinum::V1 : verinum::V0); - v >>= 1; + if (use_len <= 8 * sizeof(unsigned long)) { + /* Use native unsigned division to do the work. */ + + unsigned long l = left.as_ulong(); + unsigned long r = right.as_ulong(); + unsigned long v = l / r; + for (unsigned idx = 0 ; idx < use_len ; idx += 1) { + result.set(idx, (v & 1)? verinum::V1 : verinum::V0); + v >>= 1; + } + + } else { + result = unsigned_divide(left, right); } } @@ -857,6 +926,9 @@ verinum::V operator ^ (verinum::V l, verinum::V r) /* * $Log: verinum.cc,v $ + * Revision 1.42 2004/02/17 06:52:55 steve + * Support unsigned divide of huge numbers. + * * Revision 1.41 2003/10/26 04:54:56 steve * Support constant evaluation of binary ^ operator. * diff --git a/verinum.h b/verinum.h index 50099ab9a..85c9578f0 100644 --- a/verinum.h +++ b/verinum.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: verinum.h,v 1.25 2003/10/26 04:54:56 steve Exp $" +#ident "$Id: verinum.h,v 1.26 2004/02/17 06:52:55 steve Exp $" #endif # include @@ -139,11 +139,17 @@ extern verinum operator * (const verinum&left, const verinum&right); extern verinum operator / (const verinum&left, const verinum&right); extern verinum operator % (const verinum&left, const verinum&right); +extern verinum operator<< (const verinum&left, unsigned shift); +extern verinum operator>> (const verinum&left, unsigned shift); + /* Bitwise not returns the ones complement. */ extern verinum v_not(const verinum&left); /* * $Log: verinum.h,v $ + * Revision 1.26 2004/02/17 06:52:55 steve + * Support unsigned divide of huge numbers. + * * Revision 1.25 2003/10/26 04:54:56 steve * Support constant evaluation of binary ^ operator. *