Support for wide modulus operations.

Compile time support for wide modulus.

Signed-off-by: Stephen Williams <steve@icarus.com>
This commit is contained in:
Stephen Williams 2007-10-09 21:40:08 -07:00
parent a0b1272a62
commit e97bdf8b21
1 changed files with 45 additions and 10 deletions

View File

@ -912,6 +912,36 @@ static verinum unsigned_divide(verinum num, verinum den)
return result; return result;
} }
static verinum unsigned_modulus(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 num;
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 num;
}
/* /*
* This operator divides the left number by the right number. If * This operator divides the left number by the right number. If
* either value is signed, the result is signed. If both values have a * either value is signed, the result is signed. If both values have a
@ -1039,20 +1069,25 @@ verinum operator % (const verinum&left, const verinum&right)
} else { } else {
/* XXXX FIXME XXXX Use native unsigned division to do /* Use native unsigned division, if possible, to do
the work. This does not work if the result is too the work. This does not work if the result is too
large for the native integer. */ large for the native integer, so resort to a modulus
assert(use_len <= 8*sizeof(unsigned long)); function in that case. */
unsigned long l = left.as_ulong(); if (use_len <= 8*sizeof(unsigned long)) {
unsigned long r = right.as_ulong(); assert(use_len <= 8*sizeof(unsigned long));
unsigned long v = l % r; unsigned long l = left.as_ulong();
for (unsigned idx = 0 ; idx < use_len ; idx += 1) { unsigned long r = right.as_ulong();
result.set(idx, (v & 1)? verinum::V1 : verinum::V0); unsigned long v = l % r;
v >>= 1; for (unsigned idx = 0 ; idx < use_len ; idx += 1) {
result.set(idx, (v & 1)? verinum::V1 : verinum::V0);
v >>= 1;
}
} else {
result = unsigned_modulus(left, right);
} }
} }
return result; return trim_vnum(result);
} }
verinum concat(const verinum&left, const verinum&right) verinum concat(const verinum&left, const verinum&right)