mirror of
https://github.com/opnsense/src.git
synced 2026-02-16 09:08:51 -05:00
issues in these areas:
.h's installed
.hP's installed
-lcurses interaction
files needed in ~/legal for copyleft reasons.
2280 lines
46 KiB
C++
2280 lines
46 KiB
C++
/*
|
|
Copyright (C) 1988 Free Software Foundation
|
|
written by Doug Lea (dl@rocky.oswego.edu)
|
|
|
|
This file is part of the GNU C++ Library. This library is free
|
|
software; you can redistribute it and/or modify it under the terms of
|
|
the GNU Library General Public License as published by the Free
|
|
Software Foundation; either version 2 of the License, or (at your
|
|
option) any later version. This 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 Library General Public License for more details.
|
|
You should have received a copy of the GNU Library General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
/*
|
|
Some of the following algorithms are very loosely based on those from
|
|
MIT C-Scheme bignum.c, which is
|
|
Copyright (c) 1987 Massachusetts Institute of Technology
|
|
|
|
with other guidance from Knuth, vol. 2
|
|
|
|
Thanks to the creators of the algorithms.
|
|
*/
|
|
|
|
#ifdef __GNUG__
|
|
#pragma implementation
|
|
#endif
|
|
#include <Integer.h>
|
|
#include <std.h>
|
|
#include <ctype.h>
|
|
#include <limits.h>
|
|
#include <Obstack.h>
|
|
#include <AllocRing.h>
|
|
#include <new.h>
|
|
#include <builtin.h>
|
|
#include "Integer.hP"
|
|
|
|
IntRep _ZeroRep = {1, 0, 1, {0}};
|
|
IntRep _OneRep = {1, 0, 1, {1}};
|
|
IntRep _MinusOneRep = {1, 0, 0, {1}};
|
|
|
|
|
|
// utilities to extract and transfer bits
|
|
|
|
// get low bits
|
|
|
|
inline static unsigned short extract(unsigned long x)
|
|
{
|
|
return x & I_MAXNUM;
|
|
}
|
|
|
|
// transfer high bits to low
|
|
|
|
inline static unsigned long down(unsigned long x)
|
|
{
|
|
return (x >> I_SHIFT) & I_MAXNUM;
|
|
}
|
|
|
|
// transfer low bits to high
|
|
|
|
inline static unsigned long up(unsigned long x)
|
|
{
|
|
return x << I_SHIFT;
|
|
}
|
|
|
|
// compare two equal-length reps
|
|
|
|
inline static int docmp(const unsigned short* x, const unsigned short* y, int l)
|
|
{
|
|
int diff = 0;
|
|
const unsigned short* xs = &(x[l]);
|
|
const unsigned short* ys = &(y[l]);
|
|
while (l-- > 0 && (diff = (*--xs) - (*--ys)) == 0);
|
|
return diff;
|
|
}
|
|
|
|
// figure out max length of result of +, -, etc.
|
|
|
|
inline static int calc_len(int len1, int len2, int pad)
|
|
{
|
|
return (len1 >= len2)? len1 + pad : len2 + pad;
|
|
}
|
|
|
|
// ensure len & sgn are correct
|
|
|
|
inline static void Icheck(IntRep* rep)
|
|
{
|
|
int l = rep->len;
|
|
const unsigned short* p = &(rep->s[l]);
|
|
while (l > 0 && *--p == 0) --l;
|
|
if ((rep->len = l) == 0) rep->sgn = I_POSITIVE;
|
|
}
|
|
|
|
|
|
// zero out the end of a rep
|
|
|
|
inline static void Iclear_from(IntRep* rep, int p)
|
|
{
|
|
unsigned short* cp = &(rep->s[p]);
|
|
const unsigned short* cf = &(rep->s[rep->len]);
|
|
while(cp < cf) *cp++ = 0;
|
|
}
|
|
|
|
// copy parts of a rep
|
|
|
|
static inline void scpy(const unsigned short* src, unsigned short* dest,int nb)
|
|
{
|
|
while (--nb >= 0) *dest++ = *src++;
|
|
}
|
|
|
|
// make sure an argument is valid
|
|
|
|
static inline void nonnil(const IntRep* rep)
|
|
{
|
|
if (rep == 0)
|
|
(*lib_error_handler)("Integer", "operation on uninitialized Integer");
|
|
}
|
|
|
|
// allocate a new Irep. Pad to something close to a power of two.
|
|
|
|
inline static IntRep* Inew(int newlen)
|
|
{
|
|
unsigned int siz = sizeof(IntRep) + newlen * sizeof(short) +
|
|
MALLOC_MIN_OVERHEAD;
|
|
unsigned int allocsiz = MINIntRep_SIZE;
|
|
while (allocsiz < siz) allocsiz <<= 1; // find a power of 2
|
|
allocsiz -= MALLOC_MIN_OVERHEAD;
|
|
if (allocsiz >= MAXIntRep_SIZE * sizeof(short))
|
|
(*lib_error_handler)("Integer", "Requested length out of range");
|
|
|
|
IntRep* rep = (IntRep *) new char[allocsiz];
|
|
rep->sz = (allocsiz - sizeof(IntRep) + sizeof(short)) / sizeof(short);
|
|
return rep;
|
|
}
|
|
|
|
// allocate: use the bits in src if non-null, clear the rest
|
|
|
|
IntRep* Ialloc(IntRep* old, const unsigned short* src, int srclen, int newsgn,
|
|
int newlen)
|
|
{
|
|
IntRep* rep;
|
|
if (old == 0 || newlen > old->sz)
|
|
rep = Inew(newlen);
|
|
else
|
|
rep = old;
|
|
|
|
rep->len = newlen;
|
|
rep->sgn = newsgn;
|
|
|
|
scpy(src, rep->s, srclen);
|
|
Iclear_from(rep, srclen);
|
|
|
|
if (old != rep && old != 0 && !STATIC_IntRep(old)) delete old;
|
|
return rep;
|
|
}
|
|
|
|
// allocate and clear
|
|
|
|
IntRep* Icalloc(IntRep* old, int newlen)
|
|
{
|
|
IntRep* rep;
|
|
if (old == 0 || newlen > old->sz)
|
|
{
|
|
if (old != 0 && !STATIC_IntRep(old)) delete old;
|
|
rep = Inew(newlen);
|
|
}
|
|
else
|
|
rep = old;
|
|
|
|
rep->len = newlen;
|
|
rep->sgn = I_POSITIVE;
|
|
Iclear_from(rep, 0);
|
|
|
|
return rep;
|
|
}
|
|
|
|
// reallocate
|
|
|
|
IntRep* Iresize(IntRep* old, int newlen)
|
|
{
|
|
IntRep* rep;
|
|
unsigned short oldlen;
|
|
if (old == 0)
|
|
{
|
|
oldlen = 0;
|
|
rep = Inew(newlen);
|
|
rep->sgn = I_POSITIVE;
|
|
}
|
|
else
|
|
{
|
|
oldlen = old->len;
|
|
if (newlen > old->sz)
|
|
{
|
|
rep = Inew(newlen);
|
|
scpy(old->s, rep->s, oldlen);
|
|
rep->sgn = old->sgn;
|
|
if (!STATIC_IntRep(old)) delete old;
|
|
}
|
|
else
|
|
rep = old;
|
|
}
|
|
|
|
rep->len = newlen;
|
|
Iclear_from(rep, oldlen);
|
|
|
|
return rep;
|
|
}
|
|
|
|
|
|
// same, for straight copy
|
|
|
|
IntRep* Icopy(IntRep* old, const IntRep* src)
|
|
{
|
|
if (old == src) return old;
|
|
IntRep* rep;
|
|
if (src == 0)
|
|
{
|
|
if (old == 0)
|
|
rep = Inew(0);
|
|
else
|
|
{
|
|
rep = old;
|
|
Iclear_from(rep, 0);
|
|
}
|
|
rep->len = 0;
|
|
rep->sgn = I_POSITIVE;
|
|
}
|
|
else
|
|
{
|
|
int newlen = src->len;
|
|
if (old == 0 || newlen > old->sz)
|
|
{
|
|
if (old != 0 && !STATIC_IntRep(old)) delete old;
|
|
rep = Inew(newlen);
|
|
}
|
|
else
|
|
rep = old;
|
|
|
|
rep->len = newlen;
|
|
rep->sgn = src->sgn;
|
|
|
|
scpy(src->s, rep->s, newlen);
|
|
}
|
|
|
|
return rep;
|
|
}
|
|
|
|
// allocate & copy space for a long
|
|
|
|
IntRep* Icopy_long(IntRep* old, long x)
|
|
{
|
|
int newsgn = (x >= 0);
|
|
IntRep* rep = Icopy_ulong(old, newsgn ? x : -x);
|
|
rep->sgn = newsgn;
|
|
return rep;
|
|
}
|
|
|
|
IntRep* Icopy_ulong(IntRep* old, unsigned long x)
|
|
{
|
|
unsigned short src[SHORT_PER_LONG];
|
|
|
|
unsigned short srclen = 0;
|
|
while (x != 0)
|
|
{
|
|
src[srclen++] = extract(x);
|
|
x = down(x);
|
|
}
|
|
|
|
IntRep* rep;
|
|
if (old == 0 || srclen > old->sz)
|
|
{
|
|
if (old != 0 && !STATIC_IntRep(old)) delete old;
|
|
rep = Inew(srclen);
|
|
}
|
|
else
|
|
rep = old;
|
|
|
|
rep->len = srclen;
|
|
rep->sgn = I_POSITIVE;
|
|
|
|
scpy(src, rep->s, srclen);
|
|
|
|
return rep;
|
|
}
|
|
|
|
// special case for zero -- it's worth it!
|
|
|
|
IntRep* Icopy_zero(IntRep* old)
|
|
{
|
|
if (old == 0 || STATIC_IntRep(old))
|
|
return &_ZeroRep;
|
|
|
|
old->len = 0;
|
|
old->sgn = I_POSITIVE;
|
|
|
|
return old;
|
|
}
|
|
|
|
// special case for 1 or -1
|
|
|
|
IntRep* Icopy_one(IntRep* old, int newsgn)
|
|
{
|
|
if (old == 0 || 1 > old->sz)
|
|
{
|
|
if (old != 0 && !STATIC_IntRep(old)) delete old;
|
|
return newsgn==I_NEGATIVE ? &_MinusOneRep : &_OneRep;
|
|
}
|
|
|
|
old->sgn = newsgn;
|
|
old->len = 1;
|
|
old->s[0] = 1;
|
|
|
|
return old;
|
|
}
|
|
|
|
// convert to a legal two's complement long if possible
|
|
// if too big, return most negative/positive value
|
|
|
|
long Itolong(const IntRep* rep)
|
|
{
|
|
if ((unsigned)(rep->len) > (unsigned)(SHORT_PER_LONG))
|
|
return (rep->sgn == I_POSITIVE) ? LONG_MAX : LONG_MIN;
|
|
else if (rep->len == 0)
|
|
return 0;
|
|
else if ((unsigned)(rep->len) < (unsigned)(SHORT_PER_LONG))
|
|
{
|
|
unsigned long a = rep->s[rep->len-1];
|
|
if (SHORT_PER_LONG > 2) // normally optimized out
|
|
{
|
|
for (int i = rep->len - 2; i >= 0; --i)
|
|
a = up(a) | rep->s[i];
|
|
}
|
|
return (rep->sgn == I_POSITIVE)? a : -((long)a);
|
|
}
|
|
else
|
|
{
|
|
unsigned long a = rep->s[SHORT_PER_LONG - 1];
|
|
if (a >= I_MINNUM)
|
|
return (rep->sgn == I_POSITIVE) ? LONG_MAX : LONG_MIN;
|
|
else
|
|
{
|
|
a = up(a) | rep->s[SHORT_PER_LONG - 2];
|
|
if (SHORT_PER_LONG > 2)
|
|
{
|
|
for (int i = SHORT_PER_LONG - 3; i >= 0; --i)
|
|
a = up(a) | rep->s[i];
|
|
}
|
|
return (rep->sgn == I_POSITIVE)? a : -((long)a);
|
|
}
|
|
}
|
|
}
|
|
|
|
// test whether op long() will work.
|
|
// careful about asymmetry between LONG_MIN & LONG_MAX
|
|
|
|
int Iislong(const IntRep* rep)
|
|
{
|
|
unsigned int l = rep->len;
|
|
if (l < SHORT_PER_LONG)
|
|
return 1;
|
|
else if (l > SHORT_PER_LONG)
|
|
return 0;
|
|
else if ((unsigned)(rep->s[SHORT_PER_LONG - 1]) < (unsigned)(I_MINNUM))
|
|
return 1;
|
|
else if (rep->sgn == I_NEGATIVE && rep->s[SHORT_PER_LONG - 1] == I_MINNUM)
|
|
{
|
|
for (unsigned int i = 0; i < SHORT_PER_LONG - 1; ++i)
|
|
if (rep->s[i] != 0)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
// comparison functions
|
|
|
|
int compare(const IntRep* x, const IntRep* y)
|
|
{
|
|
int diff = x->sgn - y->sgn;
|
|
if (diff == 0)
|
|
{
|
|
diff = x->len - y->len;
|
|
if (diff == 0)
|
|
diff = docmp(x->s, y->s, x->len);
|
|
if (x->sgn == I_NEGATIVE)
|
|
diff = -diff;
|
|
}
|
|
return diff;
|
|
}
|
|
|
|
int ucompare(const IntRep* x, const IntRep* y)
|
|
{
|
|
int diff = x->len - y->len;
|
|
if (diff == 0)
|
|
{
|
|
int l = x->len;
|
|
const unsigned short* xs = &(x->s[l]);
|
|
const unsigned short* ys = &(y->s[l]);
|
|
while (l-- > 0 && (diff = (*--xs) - (*--ys)) == 0);
|
|
}
|
|
return diff;
|
|
}
|
|
|
|
int compare(const IntRep* x, long y)
|
|
{
|
|
int xl = x->len;
|
|
int xsgn = x->sgn;
|
|
if (y == 0)
|
|
{
|
|
if (xl == 0)
|
|
return 0;
|
|
else if (xsgn == I_NEGATIVE)
|
|
return -1;
|
|
else
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
int ysgn = y >= 0;
|
|
unsigned long uy = (ysgn)? y : -y;
|
|
int diff = xsgn - ysgn;
|
|
if (diff == 0)
|
|
{
|
|
diff = xl - SHORT_PER_LONG;
|
|
if (diff <= 0)
|
|
{
|
|
unsigned short tmp[SHORT_PER_LONG];
|
|
int yl = 0;
|
|
while (uy != 0)
|
|
{
|
|
tmp[yl++] = extract(uy);
|
|
uy = down(uy);
|
|
}
|
|
diff = xl - yl;
|
|
if (diff == 0)
|
|
diff = docmp(x->s, tmp, xl);
|
|
}
|
|
if (xsgn == I_NEGATIVE)
|
|
diff = -diff;
|
|
}
|
|
return diff;
|
|
}
|
|
}
|
|
|
|
int ucompare(const IntRep* x, long y)
|
|
{
|
|
int xl = x->len;
|
|
if (y == 0)
|
|
return xl;
|
|
else
|
|
{
|
|
unsigned long uy = (y >= 0)? y : -y;
|
|
int diff = xl - SHORT_PER_LONG;
|
|
if (diff <= 0)
|
|
{
|
|
unsigned short tmp[SHORT_PER_LONG];
|
|
int yl = 0;
|
|
while (uy != 0)
|
|
{
|
|
tmp[yl++] = extract(uy);
|
|
uy = down(uy);
|
|
}
|
|
diff = xl - yl;
|
|
if (diff == 0)
|
|
diff = docmp(x->s, tmp, xl);
|
|
}
|
|
return diff;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// arithmetic functions
|
|
|
|
IntRep* add(const IntRep* x, int negatex,
|
|
const IntRep* y, int negatey, IntRep* r)
|
|
{
|
|
nonnil(x);
|
|
nonnil(y);
|
|
|
|
int xl = x->len;
|
|
int yl = y->len;
|
|
|
|
int xsgn = (negatex && xl != 0) ? !x->sgn : x->sgn;
|
|
int ysgn = (negatey && yl != 0) ? !y->sgn : y->sgn;
|
|
|
|
int xrsame = x == r;
|
|
int yrsame = y == r;
|
|
|
|
if (yl == 0)
|
|
r = Ialloc(r, x->s, xl, xsgn, xl);
|
|
else if (xl == 0)
|
|
r = Ialloc(r, y->s, yl, ysgn, yl);
|
|
else if (xsgn == ysgn)
|
|
{
|
|
if (xrsame || yrsame)
|
|
r = Iresize(r, calc_len(xl, yl, 1));
|
|
else
|
|
r = Icalloc(r, calc_len(xl, yl, 1));
|
|
r->sgn = xsgn;
|
|
unsigned short* rs = r->s;
|
|
const unsigned short* as;
|
|
const unsigned short* bs;
|
|
const unsigned short* topa;
|
|
const unsigned short* topb;
|
|
if (xl >= yl)
|
|
{
|
|
as = (xrsame)? r->s : x->s;
|
|
topa = &(as[xl]);
|
|
bs = (yrsame)? r->s : y->s;
|
|
topb = &(bs[yl]);
|
|
}
|
|
else
|
|
{
|
|
bs = (xrsame)? r->s : x->s;
|
|
topb = &(bs[xl]);
|
|
as = (yrsame)? r->s : y->s;
|
|
topa = &(as[yl]);
|
|
}
|
|
unsigned long sum = 0;
|
|
while (bs < topb)
|
|
{
|
|
sum += (unsigned long)(*as++) + (unsigned long)(*bs++);
|
|
*rs++ = extract(sum);
|
|
sum = down(sum);
|
|
}
|
|
while (sum != 0 && as < topa)
|
|
{
|
|
sum += (unsigned long)(*as++);
|
|
*rs++ = extract(sum);
|
|
sum = down(sum);
|
|
}
|
|
if (sum != 0)
|
|
*rs = extract(sum);
|
|
else if (rs != as)
|
|
while (as < topa)
|
|
*rs++ = *as++;
|
|
}
|
|
else
|
|
{
|
|
int comp = ucompare(x, y);
|
|
if (comp == 0)
|
|
r = Icopy_zero(r);
|
|
else
|
|
{
|
|
if (xrsame || yrsame)
|
|
r = Iresize(r, calc_len(xl, yl, 0));
|
|
else
|
|
r = Icalloc(r, calc_len(xl, yl, 0));
|
|
unsigned short* rs = r->s;
|
|
const unsigned short* as;
|
|
const unsigned short* bs;
|
|
const unsigned short* topa;
|
|
const unsigned short* topb;
|
|
if (comp > 0)
|
|
{
|
|
as = (xrsame)? r->s : x->s;
|
|
topa = &(as[xl]);
|
|
bs = (yrsame)? r->s : y->s;
|
|
topb = &(bs[yl]);
|
|
r->sgn = xsgn;
|
|
}
|
|
else
|
|
{
|
|
bs = (xrsame)? r->s : x->s;
|
|
topb = &(bs[xl]);
|
|
as = (yrsame)? r->s : y->s;
|
|
topa = &(as[yl]);
|
|
r->sgn = ysgn;
|
|
}
|
|
unsigned long hi = 1;
|
|
while (bs < topb)
|
|
{
|
|
hi += (unsigned long)(*as++) + I_MAXNUM - (unsigned long)(*bs++);
|
|
*rs++ = extract(hi);
|
|
hi = down(hi);
|
|
}
|
|
while (hi == 0 && as < topa)
|
|
{
|
|
hi = (unsigned long)(*as++) + I_MAXNUM;
|
|
*rs++ = extract(hi);
|
|
hi = down(hi);
|
|
}
|
|
if (rs != as)
|
|
while (as < topa)
|
|
*rs++ = *as++;
|
|
}
|
|
}
|
|
Icheck(r);
|
|
return r;
|
|
}
|
|
|
|
|
|
IntRep* add(const IntRep* x, int negatex, long y, IntRep* r)
|
|
{
|
|
nonnil(x);
|
|
int xl = x->len;
|
|
int xsgn = (negatex && xl != 0) ? !x->sgn : x->sgn;
|
|
int xrsame = x == r;
|
|
|
|
int ysgn = (y >= 0);
|
|
unsigned long uy = (ysgn)? y : -y;
|
|
|
|
if (y == 0)
|
|
r = Ialloc(r, x->s, xl, xsgn, xl);
|
|
else if (xl == 0)
|
|
r = Icopy_long(r, y);
|
|
else if (xsgn == ysgn)
|
|
{
|
|
if (xrsame)
|
|
r = Iresize(r, calc_len(xl, SHORT_PER_LONG, 1));
|
|
else
|
|
r = Icalloc(r, calc_len(xl, SHORT_PER_LONG, 1));
|
|
r->sgn = xsgn;
|
|
unsigned short* rs = r->s;
|
|
const unsigned short* as = (xrsame)? r->s : x->s;
|
|
const unsigned short* topa = &(as[xl]);
|
|
unsigned long sum = 0;
|
|
while (as < topa && uy != 0)
|
|
{
|
|
unsigned long u = extract(uy);
|
|
uy = down(uy);
|
|
sum += (unsigned long)(*as++) + u;
|
|
*rs++ = extract(sum);
|
|
sum = down(sum);
|
|
}
|
|
while (sum != 0 && as < topa)
|
|
{
|
|
sum += (unsigned long)(*as++);
|
|
*rs++ = extract(sum);
|
|
sum = down(sum);
|
|
}
|
|
if (sum != 0)
|
|
*rs = extract(sum);
|
|
else if (rs != as)
|
|
while (as < topa)
|
|
*rs++ = *as++;
|
|
}
|
|
else
|
|
{
|
|
unsigned short tmp[SHORT_PER_LONG];
|
|
int yl = 0;
|
|
while (uy != 0)
|
|
{
|
|
tmp[yl++] = extract(uy);
|
|
uy = down(uy);
|
|
}
|
|
int comp = xl - yl;
|
|
if (comp == 0)
|
|
comp = docmp(x->s, tmp, yl);
|
|
if (comp == 0)
|
|
r = Icopy_zero(r);
|
|
else
|
|
{
|
|
if (xrsame)
|
|
r = Iresize(r, calc_len(xl, yl, 0));
|
|
else
|
|
r = Icalloc(r, calc_len(xl, yl, 0));
|
|
unsigned short* rs = r->s;
|
|
const unsigned short* as;
|
|
const unsigned short* bs;
|
|
const unsigned short* topa;
|
|
const unsigned short* topb;
|
|
if (comp > 0)
|
|
{
|
|
as = (xrsame)? r->s : x->s;
|
|
topa = &(as[xl]);
|
|
bs = tmp;
|
|
topb = &(bs[yl]);
|
|
r->sgn = xsgn;
|
|
}
|
|
else
|
|
{
|
|
bs = (xrsame)? r->s : x->s;
|
|
topb = &(bs[xl]);
|
|
as = tmp;
|
|
topa = &(as[yl]);
|
|
r->sgn = ysgn;
|
|
}
|
|
unsigned long hi = 1;
|
|
while (bs < topb)
|
|
{
|
|
hi += (unsigned long)(*as++) + I_MAXNUM - (unsigned long)(*bs++);
|
|
*rs++ = extract(hi);
|
|
hi = down(hi);
|
|
}
|
|
while (hi == 0 && as < topa)
|
|
{
|
|
hi = (unsigned long)(*as++) + I_MAXNUM;
|
|
*rs++ = extract(hi);
|
|
hi = down(hi);
|
|
}
|
|
if (rs != as)
|
|
while (as < topa)
|
|
*rs++ = *as++;
|
|
}
|
|
}
|
|
Icheck(r);
|
|
return r;
|
|
}
|
|
|
|
|
|
IntRep* multiply(const IntRep* x, const IntRep* y, IntRep* r)
|
|
{
|
|
nonnil(x);
|
|
nonnil(y);
|
|
int xl = x->len;
|
|
int yl = y->len;
|
|
int rl = xl + yl;
|
|
int rsgn = x->sgn == y->sgn;
|
|
int xrsame = x == r;
|
|
int yrsame = y == r;
|
|
int xysame = x == y;
|
|
|
|
if (xl == 0 || yl == 0)
|
|
r = Icopy_zero(r);
|
|
else if (xl == 1 && x->s[0] == 1)
|
|
r = Icopy(r, y);
|
|
else if (yl == 1 && y->s[0] == 1)
|
|
r = Icopy(r, x);
|
|
else if (!(xysame && xrsame))
|
|
{
|
|
if (xrsame || yrsame)
|
|
r = Iresize(r, rl);
|
|
else
|
|
r = Icalloc(r, rl);
|
|
unsigned short* rs = r->s;
|
|
unsigned short* topr = &(rs[rl]);
|
|
|
|
// use best inner/outer loop params given constraints
|
|
unsigned short* currentr;
|
|
const unsigned short* bota;
|
|
const unsigned short* as;
|
|
const unsigned short* botb;
|
|
const unsigned short* topb;
|
|
if (xrsame)
|
|
{
|
|
currentr = &(rs[xl-1]);
|
|
bota = rs;
|
|
as = currentr;
|
|
botb = y->s;
|
|
topb = &(botb[yl]);
|
|
}
|
|
else if (yrsame)
|
|
{
|
|
currentr = &(rs[yl-1]);
|
|
bota = rs;
|
|
as = currentr;
|
|
botb = x->s;
|
|
topb = &(botb[xl]);
|
|
}
|
|
else if (xl <= yl)
|
|
{
|
|
currentr = &(rs[xl-1]);
|
|
bota = x->s;
|
|
as = &(bota[xl-1]);
|
|
botb = y->s;
|
|
topb = &(botb[yl]);
|
|
}
|
|
else
|
|
{
|
|
currentr = &(rs[yl-1]);
|
|
bota = y->s;
|
|
as = &(bota[yl-1]);
|
|
botb = x->s;
|
|
topb = &(botb[xl]);
|
|
}
|
|
|
|
while (as >= bota)
|
|
{
|
|
unsigned long ai = (unsigned long)(*as--);
|
|
unsigned short* rs = currentr--;
|
|
*rs = 0;
|
|
if (ai != 0)
|
|
{
|
|
unsigned long sum = 0;
|
|
const unsigned short* bs = botb;
|
|
while (bs < topb)
|
|
{
|
|
sum += ai * (unsigned long)(*bs++) + (unsigned long)(*rs);
|
|
*rs++ = extract(sum);
|
|
sum = down(sum);
|
|
}
|
|
while (sum != 0 && rs < topr)
|
|
{
|
|
sum += (unsigned long)(*rs);
|
|
*rs++ = extract(sum);
|
|
sum = down(sum);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else // x, y, and r same; compute over diagonals
|
|
{
|
|
r = Iresize(r, rl);
|
|
unsigned short* botr = r->s;
|
|
unsigned short* topr = &(botr[rl]);
|
|
unsigned short* rs = &(botr[rl - 2]);
|
|
|
|
const unsigned short* bota = (xrsame)? botr : x->s;
|
|
const unsigned short* loa = &(bota[xl - 1]);
|
|
const unsigned short* hia = loa;
|
|
|
|
for (; rs >= botr; --rs)
|
|
{
|
|
const unsigned short* h = hia;
|
|
const unsigned short* l = loa;
|
|
unsigned long prod = (unsigned long)(*h) * (unsigned long)(*l);
|
|
*rs = 0;
|
|
|
|
for(;;)
|
|
{
|
|
unsigned short* rt = rs;
|
|
unsigned long sum = prod + (unsigned long)(*rt);
|
|
*rt++ = extract(sum);
|
|
sum = down(sum);
|
|
while (sum != 0 && rt < topr)
|
|
{
|
|
sum += (unsigned long)(*rt);
|
|
*rt++ = extract(sum);
|
|
sum = down(sum);
|
|
}
|
|
if (h > l)
|
|
{
|
|
rt = rs;
|
|
sum = prod + (unsigned long)(*rt);
|
|
*rt++ = extract(sum);
|
|
sum = down(sum);
|
|
while (sum != 0 && rt < topr)
|
|
{
|
|
sum += (unsigned long)(*rt);
|
|
*rt++ = extract(sum);
|
|
sum = down(sum);
|
|
}
|
|
if (--h >= ++l)
|
|
prod = (unsigned long)(*h) * (unsigned long)(*l);
|
|
else
|
|
break;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
if (loa > bota)
|
|
--loa;
|
|
else
|
|
--hia;
|
|
}
|
|
}
|
|
r->sgn = rsgn;
|
|
Icheck(r);
|
|
return r;
|
|
}
|
|
|
|
|
|
IntRep* multiply(const IntRep* x, long y, IntRep* r)
|
|
{
|
|
nonnil(x);
|
|
int xl = x->len;
|
|
|
|
if (xl == 0 || y == 0)
|
|
r = Icopy_zero(r);
|
|
else if (y == 1)
|
|
r = Icopy(r, x);
|
|
else
|
|
{
|
|
int ysgn = y >= 0;
|
|
int rsgn = x->sgn == ysgn;
|
|
unsigned long uy = (ysgn)? y : -y;
|
|
unsigned short tmp[SHORT_PER_LONG];
|
|
int yl = 0;
|
|
while (uy != 0)
|
|
{
|
|
tmp[yl++] = extract(uy);
|
|
uy = down(uy);
|
|
}
|
|
|
|
int rl = xl + yl;
|
|
int xrsame = x == r;
|
|
if (xrsame)
|
|
r = Iresize(r, rl);
|
|
else
|
|
r = Icalloc(r, rl);
|
|
|
|
unsigned short* rs = r->s;
|
|
unsigned short* topr = &(rs[rl]);
|
|
unsigned short* currentr;
|
|
const unsigned short* bota;
|
|
const unsigned short* as;
|
|
const unsigned short* botb;
|
|
const unsigned short* topb;
|
|
|
|
if (xrsame)
|
|
{
|
|
currentr = &(rs[xl-1]);
|
|
bota = rs;
|
|
as = currentr;
|
|
botb = tmp;
|
|
topb = &(botb[yl]);
|
|
}
|
|
else if (xl <= yl)
|
|
{
|
|
currentr = &(rs[xl-1]);
|
|
bota = x->s;
|
|
as = &(bota[xl-1]);
|
|
botb = tmp;
|
|
topb = &(botb[yl]);
|
|
}
|
|
else
|
|
{
|
|
currentr = &(rs[yl-1]);
|
|
bota = tmp;
|
|
as = &(bota[yl-1]);
|
|
botb = x->s;
|
|
topb = &(botb[xl]);
|
|
}
|
|
|
|
while (as >= bota)
|
|
{
|
|
unsigned long ai = (unsigned long)(*as--);
|
|
unsigned short* rs = currentr--;
|
|
*rs = 0;
|
|
if (ai != 0)
|
|
{
|
|
unsigned long sum = 0;
|
|
const unsigned short* bs = botb;
|
|
while (bs < topb)
|
|
{
|
|
sum += ai * (unsigned long)(*bs++) + (unsigned long)(*rs);
|
|
*rs++ = extract(sum);
|
|
sum = down(sum);
|
|
}
|
|
while (sum != 0 && rs < topr)
|
|
{
|
|
sum += (unsigned long)(*rs);
|
|
*rs++ = extract(sum);
|
|
sum = down(sum);
|
|
}
|
|
}
|
|
}
|
|
r->sgn = rsgn;
|
|
}
|
|
Icheck(r);
|
|
return r;
|
|
}
|
|
|
|
|
|
// main division routine
|
|
|
|
static void do_divide(unsigned short* rs,
|
|
const unsigned short* ys, int yl,
|
|
unsigned short* qs, int ql)
|
|
{
|
|
const unsigned short* topy = &(ys[yl]);
|
|
unsigned short d1 = ys[yl - 1];
|
|
unsigned short d2 = ys[yl - 2];
|
|
|
|
int l = ql - 1;
|
|
int i = l + yl;
|
|
|
|
for (; l >= 0; --l, --i)
|
|
{
|
|
unsigned short qhat; // guess q
|
|
if (d1 == rs[i])
|
|
qhat = I_MAXNUM;
|
|
else
|
|
{
|
|
unsigned long lr = up((unsigned long)rs[i]) | rs[i-1];
|
|
qhat = lr / d1;
|
|
}
|
|
|
|
for(;;) // adjust q, use docmp to avoid overflow problems
|
|
{
|
|
unsigned short ts[3];
|
|
unsigned long prod = (unsigned long)d2 * (unsigned long)qhat;
|
|
ts[0] = extract(prod);
|
|
prod = down(prod) + (unsigned long)d1 * (unsigned long)qhat;
|
|
ts[1] = extract(prod);
|
|
ts[2] = extract(down(prod));
|
|
if (docmp(ts, &(rs[i-2]), 3) > 0)
|
|
--qhat;
|
|
else
|
|
break;
|
|
};
|
|
|
|
// multiply & subtract
|
|
|
|
const unsigned short* yt = ys;
|
|
unsigned short* rt = &(rs[l]);
|
|
unsigned long prod = 0;
|
|
unsigned long hi = 1;
|
|
while (yt < topy)
|
|
{
|
|
prod = (unsigned long)qhat * (unsigned long)(*yt++) + down(prod);
|
|
hi += (unsigned long)(*rt) + I_MAXNUM - (unsigned long)(extract(prod));
|
|
*rt++ = extract(hi);
|
|
hi = down(hi);
|
|
}
|
|
hi += (unsigned long)(*rt) + I_MAXNUM - (unsigned long)(down(prod));
|
|
*rt = extract(hi);
|
|
hi = down(hi);
|
|
|
|
// off-by-one, add back
|
|
|
|
if (hi == 0)
|
|
{
|
|
--qhat;
|
|
yt = ys;
|
|
rt = &(rs[l]);
|
|
hi = 0;
|
|
while (yt < topy)
|
|
{
|
|
hi = (unsigned long)(*rt) + (unsigned long)(*yt++) + down(hi);
|
|
*rt++ = extract(hi);
|
|
}
|
|
*rt = 0;
|
|
}
|
|
if (qs != 0)
|
|
qs[l] = qhat;
|
|
}
|
|
}
|
|
|
|
// divide by single digit, return remainder
|
|
// if q != 0, then keep the result in q, else just compute rem
|
|
|
|
static int unscale(const unsigned short* x, int xl, unsigned short y,
|
|
unsigned short* q)
|
|
{
|
|
if (xl == 0 || y == 1)
|
|
return 0;
|
|
else if (q != 0)
|
|
{
|
|
unsigned short* botq = q;
|
|
unsigned short* qs = &(botq[xl - 1]);
|
|
const unsigned short* xs = &(x[xl - 1]);
|
|
unsigned long rem = 0;
|
|
while (qs >= botq)
|
|
{
|
|
rem = up(rem) | *xs--;
|
|
unsigned long u = rem / y;
|
|
*qs-- = extract(u);
|
|
rem -= u * y;
|
|
}
|
|
int r = extract(rem);
|
|
return r;
|
|
}
|
|
else // same loop, a bit faster if just need rem
|
|
{
|
|
const unsigned short* botx = x;
|
|
const unsigned short* xs = &(botx[xl - 1]);
|
|
unsigned long rem = 0;
|
|
while (xs >= botx)
|
|
{
|
|
rem = up(rem) | *xs--;
|
|
unsigned long u = rem / y;
|
|
rem -= u * y;
|
|
}
|
|
int r = extract(rem);
|
|
return r;
|
|
}
|
|
}
|
|
|
|
|
|
IntRep* div(const IntRep* x, const IntRep* y, IntRep* q)
|
|
{
|
|
nonnil(x);
|
|
nonnil(y);
|
|
int xl = x->len;
|
|
int yl = y->len;
|
|
if (yl == 0) (*lib_error_handler)("Integer", "attempted division by zero");
|
|
|
|
int comp = ucompare(x, y);
|
|
int xsgn = x->sgn;
|
|
int ysgn = y->sgn;
|
|
|
|
int samesign = xsgn == ysgn;
|
|
|
|
if (comp < 0)
|
|
q = Icopy_zero(q);
|
|
else if (comp == 0)
|
|
q = Icopy_one(q, samesign);
|
|
else if (yl == 1)
|
|
{
|
|
q = Icopy(q, x);
|
|
unscale(q->s, q->len, y->s[0], q->s);
|
|
}
|
|
else
|
|
{
|
|
IntRep* yy = 0;
|
|
IntRep* r = 0;
|
|
unsigned short prescale = (I_RADIX / (1 + y->s[yl - 1]));
|
|
if (prescale != 1 || y == q)
|
|
{
|
|
yy = multiply(y, ((long)prescale & I_MAXNUM), yy);
|
|
r = multiply(x, ((long)prescale & I_MAXNUM), r);
|
|
}
|
|
else
|
|
{
|
|
yy = (IntRep*)y;
|
|
r = Icalloc(r, xl + 1);
|
|
scpy(x->s, r->s, xl);
|
|
}
|
|
|
|
int ql = xl - yl + 1;
|
|
|
|
q = Icalloc(q, ql);
|
|
do_divide(r->s, yy->s, yl, q->s, ql);
|
|
|
|
if (yy != y && !STATIC_IntRep(yy)) delete yy;
|
|
if (!STATIC_IntRep(r)) delete r;
|
|
}
|
|
q->sgn = samesign;
|
|
Icheck(q);
|
|
return q;
|
|
}
|
|
|
|
IntRep* div(const IntRep* x, long y, IntRep* q)
|
|
{
|
|
nonnil(x);
|
|
int xl = x->len;
|
|
if (y == 0) (*lib_error_handler)("Integer", "attempted division by zero");
|
|
|
|
unsigned short ys[SHORT_PER_LONG];
|
|
unsigned long u;
|
|
int ysgn = y >= 0;
|
|
if (ysgn)
|
|
u = y;
|
|
else
|
|
u = -y;
|
|
int yl = 0;
|
|
while (u != 0)
|
|
{
|
|
ys[yl++] = extract(u);
|
|
u = down(u);
|
|
}
|
|
|
|
int comp = xl - yl;
|
|
if (comp == 0) comp = docmp(x->s, ys, xl);
|
|
|
|
int xsgn = x->sgn;
|
|
int samesign = xsgn == ysgn;
|
|
|
|
if (comp < 0)
|
|
q = Icopy_zero(q);
|
|
else if (comp == 0)
|
|
{
|
|
q = Icopy_one(q, samesign);
|
|
}
|
|
else if (yl == 1)
|
|
{
|
|
q = Icopy(q, x);
|
|
unscale(q->s, q->len, ys[0], q->s);
|
|
}
|
|
else
|
|
{
|
|
IntRep* r = 0;
|
|
unsigned short prescale = (I_RADIX / (1 + ys[yl - 1]));
|
|
if (prescale != 1)
|
|
{
|
|
unsigned long prod = (unsigned long)prescale * (unsigned long)ys[0];
|
|
ys[0] = extract(prod);
|
|
prod = down(prod) + (unsigned long)prescale * (unsigned long)ys[1];
|
|
ys[1] = extract(prod);
|
|
r = multiply(x, ((long)prescale & I_MAXNUM), r);
|
|
}
|
|
else
|
|
{
|
|
r = Icalloc(r, xl + 1);
|
|
scpy(x->s, r->s, xl);
|
|
}
|
|
|
|
int ql = xl - yl + 1;
|
|
|
|
q = Icalloc(q, ql);
|
|
do_divide(r->s, ys, yl, q->s, ql);
|
|
|
|
if (!STATIC_IntRep(r)) delete r;
|
|
}
|
|
q->sgn = samesign;
|
|
Icheck(q);
|
|
return q;
|
|
}
|
|
|
|
|
|
void divide(const Integer& Ix, long y, Integer& Iq, long& rem)
|
|
{
|
|
const IntRep* x = Ix.rep;
|
|
nonnil(x);
|
|
IntRep* q = Iq.rep;
|
|
int xl = x->len;
|
|
if (y == 0) (*lib_error_handler)("Integer", "attempted division by zero");
|
|
|
|
unsigned short ys[SHORT_PER_LONG];
|
|
unsigned long u;
|
|
int ysgn = y >= 0;
|
|
if (ysgn)
|
|
u = y;
|
|
else
|
|
u = -y;
|
|
int yl = 0;
|
|
while (u != 0)
|
|
{
|
|
ys[yl++] = extract(u);
|
|
u = down(u);
|
|
}
|
|
|
|
int comp = xl - yl;
|
|
if (comp == 0) comp = docmp(x->s, ys, xl);
|
|
|
|
int xsgn = x->sgn;
|
|
int samesign = xsgn == ysgn;
|
|
|
|
if (comp < 0)
|
|
{
|
|
rem = Itolong(x);
|
|
q = Icopy_zero(q);
|
|
}
|
|
else if (comp == 0)
|
|
{
|
|
q = Icopy_one(q, samesign);
|
|
rem = 0;
|
|
}
|
|
else if (yl == 1)
|
|
{
|
|
q = Icopy(q, x);
|
|
rem = unscale(q->s, q->len, ys[0], q->s);
|
|
}
|
|
else
|
|
{
|
|
IntRep* r = 0;
|
|
unsigned short prescale = (I_RADIX / (1 + ys[yl - 1]));
|
|
if (prescale != 1)
|
|
{
|
|
unsigned long prod = (unsigned long)prescale * (unsigned long)ys[0];
|
|
ys[0] = extract(prod);
|
|
prod = down(prod) + (unsigned long)prescale * (unsigned long)ys[1];
|
|
ys[1] = extract(prod);
|
|
r = multiply(x, ((long)prescale & I_MAXNUM), r);
|
|
}
|
|
else
|
|
{
|
|
r = Icalloc(r, xl + 1);
|
|
scpy(x->s, r->s, xl);
|
|
}
|
|
|
|
int ql = xl - yl + 1;
|
|
|
|
q = Icalloc(q, ql);
|
|
|
|
do_divide(r->s, ys, yl, q->s, ql);
|
|
|
|
if (prescale != 1)
|
|
{
|
|
Icheck(r);
|
|
unscale(r->s, r->len, prescale, r->s);
|
|
}
|
|
Icheck(r);
|
|
rem = Itolong(r);
|
|
if (!STATIC_IntRep(r)) delete r;
|
|
}
|
|
rem = abs(rem);
|
|
if (xsgn == I_NEGATIVE) rem = -rem;
|
|
q->sgn = samesign;
|
|
Icheck(q);
|
|
Iq.rep = q;
|
|
}
|
|
|
|
|
|
void divide(const Integer& Ix, const Integer& Iy, Integer& Iq, Integer& Ir)
|
|
{
|
|
const IntRep* x = Ix.rep;
|
|
nonnil(x);
|
|
const IntRep* y = Iy.rep;
|
|
nonnil(y);
|
|
IntRep* q = Iq.rep;
|
|
IntRep* r = Ir.rep;
|
|
|
|
int xl = x->len;
|
|
int yl = y->len;
|
|
if (yl == 0)
|
|
(*lib_error_handler)("Integer", "attempted division by zero");
|
|
|
|
int comp = ucompare(x, y);
|
|
int xsgn = x->sgn;
|
|
int ysgn = y->sgn;
|
|
|
|
int samesign = xsgn == ysgn;
|
|
|
|
if (comp < 0)
|
|
{
|
|
q = Icopy_zero(q);
|
|
r = Icopy(r, x);
|
|
}
|
|
else if (comp == 0)
|
|
{
|
|
q = Icopy_one(q, samesign);
|
|
r = Icopy_zero(r);
|
|
}
|
|
else if (yl == 1)
|
|
{
|
|
q = Icopy(q, x);
|
|
int rem = unscale(q->s, q->len, y->s[0], q->s);
|
|
r = Icopy_long(r, rem);
|
|
if (rem != 0)
|
|
r->sgn = xsgn;
|
|
}
|
|
else
|
|
{
|
|
IntRep* yy = 0;
|
|
unsigned short prescale = (I_RADIX / (1 + y->s[yl - 1]));
|
|
if (prescale != 1 || y == q || y == r)
|
|
{
|
|
yy = multiply(y, ((long)prescale & I_MAXNUM), yy);
|
|
r = multiply(x, ((long)prescale & I_MAXNUM), r);
|
|
}
|
|
else
|
|
{
|
|
yy = (IntRep*)y;
|
|
r = Icalloc(r, xl + 1);
|
|
scpy(x->s, r->s, xl);
|
|
}
|
|
|
|
int ql = xl - yl + 1;
|
|
|
|
q = Icalloc(q, ql);
|
|
do_divide(r->s, yy->s, yl, q->s, ql);
|
|
|
|
if (yy != y && !STATIC_IntRep(yy)) delete yy;
|
|
if (prescale != 1)
|
|
{
|
|
Icheck(r);
|
|
unscale(r->s, r->len, prescale, r->s);
|
|
}
|
|
}
|
|
q->sgn = samesign;
|
|
Icheck(q);
|
|
Iq.rep = q;
|
|
Icheck(r);
|
|
Ir.rep = r;
|
|
}
|
|
|
|
IntRep* mod(const IntRep* x, const IntRep* y, IntRep* r)
|
|
{
|
|
nonnil(x);
|
|
nonnil(y);
|
|
int xl = x->len;
|
|
int yl = y->len;
|
|
if (yl == 0) (*lib_error_handler)("Integer", "attempted division by zero");
|
|
|
|
int comp = ucompare(x, y);
|
|
int xsgn = x->sgn;
|
|
|
|
if (comp < 0)
|
|
r = Icopy(r, x);
|
|
else if (comp == 0)
|
|
r = Icopy_zero(r);
|
|
else if (yl == 1)
|
|
{
|
|
int rem = unscale(x->s, xl, y->s[0], 0);
|
|
r = Icopy_long(r, rem);
|
|
if (rem != 0)
|
|
r->sgn = xsgn;
|
|
}
|
|
else
|
|
{
|
|
IntRep* yy = 0;
|
|
unsigned short prescale = (I_RADIX / (1 + y->s[yl - 1]));
|
|
if (prescale != 1 || y == r)
|
|
{
|
|
yy = multiply(y, ((long)prescale & I_MAXNUM), yy);
|
|
r = multiply(x, ((long)prescale & I_MAXNUM), r);
|
|
}
|
|
else
|
|
{
|
|
yy = (IntRep*)y;
|
|
r = Icalloc(r, xl + 1);
|
|
scpy(x->s, r->s, xl);
|
|
}
|
|
|
|
do_divide(r->s, yy->s, yl, 0, xl - yl + 1);
|
|
|
|
if (yy != y && !STATIC_IntRep(yy)) delete yy;
|
|
|
|
if (prescale != 1)
|
|
{
|
|
Icheck(r);
|
|
unscale(r->s, r->len, prescale, r->s);
|
|
}
|
|
}
|
|
Icheck(r);
|
|
return r;
|
|
}
|
|
|
|
IntRep* mod(const IntRep* x, long y, IntRep* r)
|
|
{
|
|
nonnil(x);
|
|
int xl = x->len;
|
|
if (y == 0) (*lib_error_handler)("Integer", "attempted division by zero");
|
|
|
|
unsigned short ys[SHORT_PER_LONG];
|
|
unsigned long u;
|
|
int ysgn = y >= 0;
|
|
if (ysgn)
|
|
u = y;
|
|
else
|
|
u = -y;
|
|
int yl = 0;
|
|
while (u != 0)
|
|
{
|
|
ys[yl++] = extract(u);
|
|
u = down(u);
|
|
}
|
|
|
|
int comp = xl - yl;
|
|
if (comp == 0) comp = docmp(x->s, ys, xl);
|
|
|
|
int xsgn = x->sgn;
|
|
|
|
if (comp < 0)
|
|
r = Icopy(r, x);
|
|
else if (comp == 0)
|
|
r = Icopy_zero(r);
|
|
else if (yl == 1)
|
|
{
|
|
int rem = unscale(x->s, xl, ys[0], 0);
|
|
r = Icopy_long(r, rem);
|
|
if (rem != 0)
|
|
r->sgn = xsgn;
|
|
}
|
|
else
|
|
{
|
|
unsigned short prescale = (I_RADIX / (1 + ys[yl - 1]));
|
|
if (prescale != 1)
|
|
{
|
|
unsigned long prod = (unsigned long)prescale * (unsigned long)ys[0];
|
|
ys[0] = extract(prod);
|
|
prod = down(prod) + (unsigned long)prescale * (unsigned long)ys[1];
|
|
ys[1] = extract(prod);
|
|
r = multiply(x, ((long)prescale & I_MAXNUM), r);
|
|
}
|
|
else
|
|
{
|
|
r = Icalloc(r, xl + 1);
|
|
scpy(x->s, r->s, xl);
|
|
}
|
|
|
|
do_divide(r->s, ys, yl, 0, xl - yl + 1);
|
|
|
|
if (prescale != 1)
|
|
{
|
|
Icheck(r);
|
|
unscale(r->s, r->len, prescale, r->s);
|
|
}
|
|
}
|
|
Icheck(r);
|
|
return r;
|
|
}
|
|
|
|
IntRep* lshift(const IntRep* x, long y, IntRep* r)
|
|
{
|
|
nonnil(x);
|
|
int xl = x->len;
|
|
if (xl == 0 || y == 0)
|
|
{
|
|
r = Icopy(r, x);
|
|
return r;
|
|
}
|
|
|
|
int xrsame = x == r;
|
|
int rsgn = x->sgn;
|
|
|
|
long ay = (y < 0)? -y : y;
|
|
int bw = ay / I_SHIFT;
|
|
int sw = ay % I_SHIFT;
|
|
|
|
if (y > 0)
|
|
{
|
|
int rl = bw + xl + 1;
|
|
if (xrsame)
|
|
r = Iresize(r, rl);
|
|
else
|
|
r = Icalloc(r, rl);
|
|
|
|
unsigned short* botr = r->s;
|
|
unsigned short* rs = &(botr[rl - 1]);
|
|
const unsigned short* botx = (xrsame)? botr : x->s;
|
|
const unsigned short* xs = &(botx[xl - 1]);
|
|
unsigned long a = 0;
|
|
while (xs >= botx)
|
|
{
|
|
a = up(a) | ((unsigned long)(*xs--) << sw);
|
|
*rs-- = extract(down(a));
|
|
}
|
|
*rs-- = extract(a);
|
|
while (rs >= botr)
|
|
*rs-- = 0;
|
|
}
|
|
else
|
|
{
|
|
int rl = xl - bw;
|
|
if (rl < 0)
|
|
r = Icopy_zero(r);
|
|
else
|
|
{
|
|
if (xrsame)
|
|
r = Iresize(r, rl);
|
|
else
|
|
r = Icalloc(r, rl);
|
|
int rw = I_SHIFT - sw;
|
|
unsigned short* rs = r->s;
|
|
unsigned short* topr = &(rs[rl]);
|
|
const unsigned short* botx = (xrsame)? rs : x->s;
|
|
const unsigned short* xs = &(botx[bw]);
|
|
const unsigned short* topx = &(botx[xl]);
|
|
unsigned long a = (unsigned long)(*xs++) >> sw;
|
|
while (xs < topx)
|
|
{
|
|
a |= (unsigned long)(*xs++) << rw;
|
|
*rs++ = extract(a);
|
|
a = down(a);
|
|
}
|
|
*rs++ = extract(a);
|
|
if (xrsame) topr = (unsigned short*)topx;
|
|
while (rs < topr)
|
|
*rs++ = 0;
|
|
}
|
|
}
|
|
r->sgn = rsgn;
|
|
Icheck(r);
|
|
return r;
|
|
}
|
|
|
|
IntRep* lshift(const IntRep* x, const IntRep* yy, int negatey, IntRep* r)
|
|
{
|
|
long y = Itolong(yy);
|
|
if (negatey)
|
|
y = -y;
|
|
|
|
return lshift(x, y, r);
|
|
}
|
|
|
|
IntRep* bitop(const IntRep* x, const IntRep* y, IntRep* r, char op)
|
|
{
|
|
nonnil(x);
|
|
nonnil(y);
|
|
int xl = x->len;
|
|
int yl = y->len;
|
|
int xsgn = x->sgn;
|
|
int xrsame = x == r;
|
|
int yrsame = y == r;
|
|
if (xrsame || yrsame)
|
|
r = Iresize(r, calc_len(xl, yl, 0));
|
|
else
|
|
r = Icalloc(r, calc_len(xl, yl, 0));
|
|
r->sgn = xsgn;
|
|
unsigned short* rs = r->s;
|
|
unsigned short* topr = &(rs[r->len]);
|
|
const unsigned short* as;
|
|
const unsigned short* bs;
|
|
const unsigned short* topb;
|
|
if (xl >= yl)
|
|
{
|
|
as = (xrsame)? rs : x->s;
|
|
bs = (yrsame)? rs : y->s;
|
|
topb = &(bs[yl]);
|
|
}
|
|
else
|
|
{
|
|
bs = (xrsame)? rs : x->s;
|
|
topb = &(bs[xl]);
|
|
as = (yrsame)? rs : y->s;
|
|
}
|
|
|
|
switch (op)
|
|
{
|
|
case '&':
|
|
while (bs < topb) *rs++ = *as++ & *bs++;
|
|
while (rs < topr) *rs++ = 0;
|
|
break;
|
|
case '|':
|
|
while (bs < topb) *rs++ = *as++ | *bs++;
|
|
while (rs < topr) *rs++ = *as++;
|
|
break;
|
|
case '^':
|
|
while (bs < topb) *rs++ = *as++ ^ *bs++;
|
|
while (rs < topr) *rs++ = *as++;
|
|
break;
|
|
}
|
|
Icheck(r);
|
|
return r;
|
|
}
|
|
|
|
IntRep* bitop(const IntRep* x, long y, IntRep* r, char op)
|
|
{
|
|
nonnil(x);
|
|
unsigned short tmp[SHORT_PER_LONG];
|
|
unsigned long u;
|
|
int newsgn;
|
|
if (newsgn = (y >= 0))
|
|
u = y;
|
|
else
|
|
u = -y;
|
|
|
|
int l = 0;
|
|
while (u != 0)
|
|
{
|
|
tmp[l++] = extract(u);
|
|
u = down(u);
|
|
}
|
|
|
|
int xl = x->len;
|
|
int yl = l;
|
|
int xsgn = x->sgn;
|
|
int xrsame = x == r;
|
|
if (xrsame)
|
|
r = Iresize(r, calc_len(xl, yl, 0));
|
|
else
|
|
r = Icalloc(r, calc_len(xl, yl, 0));
|
|
r->sgn = xsgn;
|
|
unsigned short* rs = r->s;
|
|
unsigned short* topr = &(rs[r->len]);
|
|
const unsigned short* as;
|
|
const unsigned short* bs;
|
|
const unsigned short* topb;
|
|
if (xl >= yl)
|
|
{
|
|
as = (xrsame)? rs : x->s;
|
|
bs = tmp;
|
|
topb = &(bs[yl]);
|
|
}
|
|
else
|
|
{
|
|
bs = (xrsame)? rs : x->s;
|
|
topb = &(bs[xl]);
|
|
as = tmp;
|
|
}
|
|
|
|
switch (op)
|
|
{
|
|
case '&':
|
|
while (bs < topb) *rs++ = *as++ & *bs++;
|
|
while (rs < topr) *rs++ = 0;
|
|
break;
|
|
case '|':
|
|
while (bs < topb) *rs++ = *as++ | *bs++;
|
|
while (rs < topr) *rs++ = *as++;
|
|
break;
|
|
case '^':
|
|
while (bs < topb) *rs++ = *as++ ^ *bs++;
|
|
while (rs < topr) *rs++ = *as++;
|
|
break;
|
|
}
|
|
Icheck(r);
|
|
return r;
|
|
}
|
|
|
|
|
|
|
|
IntRep* compl(const IntRep* src, IntRep* r)
|
|
{
|
|
nonnil(src);
|
|
r = Icopy(r, src);
|
|
unsigned short* s = r->s;
|
|
unsigned short* top = &(s[r->len - 1]);
|
|
while (s < top)
|
|
{
|
|
unsigned short cmp = ~(*s);
|
|
*s++ = cmp;
|
|
}
|
|
unsigned short a = *s;
|
|
unsigned short b = 0;
|
|
while (a != 0)
|
|
{
|
|
b <<= 1;
|
|
if (!(a & 1)) b |= 1;
|
|
a >>= 1;
|
|
}
|
|
*s = b;
|
|
Icheck(r);
|
|
return r;
|
|
}
|
|
|
|
void (setbit)(Integer& x, long b)
|
|
{
|
|
if (b >= 0)
|
|
{
|
|
int bw = (unsigned long)b / I_SHIFT;
|
|
int sw = (unsigned long)b % I_SHIFT;
|
|
int xl = x.rep ? x.rep->len : 0;
|
|
if (xl <= bw)
|
|
x.rep = Iresize(x.rep, calc_len(xl, bw+1, 0));
|
|
x.rep->s[bw] |= (1 << sw);
|
|
Icheck(x.rep);
|
|
}
|
|
}
|
|
|
|
void clearbit(Integer& x, long b)
|
|
{
|
|
if (b >= 0)
|
|
{
|
|
if (x.rep == 0)
|
|
x.rep = &_ZeroRep;
|
|
else
|
|
{
|
|
int bw = (unsigned long)b / I_SHIFT;
|
|
int sw = (unsigned long)b % I_SHIFT;
|
|
if (x.rep->len > bw)
|
|
x.rep->s[bw] &= ~(1 << sw);
|
|
}
|
|
Icheck(x.rep);
|
|
}
|
|
}
|
|
|
|
int testbit(const Integer& x, long b)
|
|
{
|
|
if (x.rep != 0 && b >= 0)
|
|
{
|
|
int bw = (unsigned long)b / I_SHIFT;
|
|
int sw = (unsigned long)b % I_SHIFT;
|
|
return (bw < x.rep->len && (x.rep->s[bw] & (1 << sw)) != 0);
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
// A version of knuth's algorithm B / ex. 4.5.3.34
|
|
// A better version that doesn't bother shifting all of `t' forthcoming
|
|
|
|
IntRep* gcd(const IntRep* x, const IntRep* y)
|
|
{
|
|
nonnil(x);
|
|
nonnil(y);
|
|
int ul = x->len;
|
|
int vl = y->len;
|
|
|
|
if (vl == 0)
|
|
return Ialloc(0, x->s, ul, I_POSITIVE, ul);
|
|
else if (ul == 0)
|
|
return Ialloc(0, y->s, vl, I_POSITIVE, vl);
|
|
|
|
IntRep* u = Ialloc(0, x->s, ul, I_POSITIVE, ul);
|
|
IntRep* v = Ialloc(0, y->s, vl, I_POSITIVE, vl);
|
|
|
|
// find shift so that both not even
|
|
|
|
long k = 0;
|
|
int l = (ul <= vl)? ul : vl;
|
|
int cont = 1;
|
|
for (int i = 0; i < l && cont; ++i)
|
|
{
|
|
unsigned long a = (i < ul)? u->s[i] : 0;
|
|
unsigned long b = (i < vl)? v->s[i] : 0;
|
|
for (int j = 0; j < I_SHIFT; ++j)
|
|
{
|
|
if ((a | b) & 1)
|
|
{
|
|
cont = 0;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
++k;
|
|
a >>= 1;
|
|
b >>= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (k != 0)
|
|
{
|
|
u = lshift(u, -k, u);
|
|
v = lshift(v, -k, v);
|
|
}
|
|
|
|
IntRep* t;
|
|
if (u->s[0] & 01)
|
|
t = Ialloc(0, v->s, v->len, !v->sgn, v->len);
|
|
else
|
|
t = Ialloc(0, u->s, u->len, u->sgn, u->len);
|
|
|
|
while (t->len != 0)
|
|
{
|
|
long s = 0; // shift t until odd
|
|
cont = 1;
|
|
int tl = t->len;
|
|
for (i = 0; i < tl && cont; ++i)
|
|
{
|
|
unsigned long a = t->s[i];
|
|
for (int j = 0; j < I_SHIFT; ++j)
|
|
{
|
|
if (a & 1)
|
|
{
|
|
cont = 0;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
++s;
|
|
a >>= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (s != 0) t = lshift(t, -s, t);
|
|
|
|
if (t->sgn == I_POSITIVE)
|
|
{
|
|
u = Icopy(u, t);
|
|
t = add(t, 0, v, 1, t);
|
|
}
|
|
else
|
|
{
|
|
v = Ialloc(v, t->s, t->len, !t->sgn, t->len);
|
|
t = add(t, 0, u, 0, t);
|
|
}
|
|
}
|
|
if (!STATIC_IntRep(t)) delete t;
|
|
if (!STATIC_IntRep(v)) delete v;
|
|
if (k != 0) u = lshift(u, k, u);
|
|
return u;
|
|
}
|
|
|
|
|
|
|
|
long lg(const IntRep* x)
|
|
{
|
|
nonnil(x);
|
|
int xl = x->len;
|
|
if (xl == 0)
|
|
return 0;
|
|
|
|
long l = (xl - 1) * I_SHIFT - 1;
|
|
unsigned short a = x->s[xl-1];
|
|
|
|
while (a != 0)
|
|
{
|
|
a = a >> 1;
|
|
++l;
|
|
}
|
|
return l;
|
|
}
|
|
|
|
IntRep* power(const IntRep* x, long y, IntRep* r)
|
|
{
|
|
nonnil(x);
|
|
int sgn;
|
|
if (x->sgn == I_POSITIVE || (!(y & 1)))
|
|
sgn = I_POSITIVE;
|
|
else
|
|
sgn = I_NEGATIVE;
|
|
|
|
int xl = x->len;
|
|
|
|
if (y == 0 || (xl == 1 && x->s[0] == 1))
|
|
r = Icopy_one(r, sgn);
|
|
else if (xl == 0 || y < 0)
|
|
r = Icopy_zero(r);
|
|
else if (y == 1 || y == -1)
|
|
r = Icopy(r, x);
|
|
else
|
|
{
|
|
int maxsize = ((lg(x) + 1) * y) / I_SHIFT + 2; // pre-allocate space
|
|
IntRep* b = Ialloc(0, x->s, xl, I_POSITIVE, maxsize);
|
|
b->len = xl;
|
|
r = Icalloc(r, maxsize);
|
|
r = Icopy_one(r, I_POSITIVE);
|
|
for(;;)
|
|
{
|
|
if (y & 1)
|
|
r = multiply(r, b, r);
|
|
if ((y >>= 1) == 0)
|
|
break;
|
|
else
|
|
b = multiply(b, b, b);
|
|
}
|
|
if (!STATIC_IntRep(b)) delete b;
|
|
}
|
|
r->sgn = sgn;
|
|
Icheck(r);
|
|
return r;
|
|
}
|
|
|
|
IntRep* abs(const IntRep* src, IntRep* dest)
|
|
{
|
|
nonnil(src);
|
|
if (src != dest)
|
|
dest = Icopy(dest, src);
|
|
dest->sgn = I_POSITIVE;
|
|
return dest;
|
|
}
|
|
|
|
IntRep* negate(const IntRep* src, IntRep* dest)
|
|
{
|
|
nonnil(src);
|
|
if (src != dest)
|
|
dest = Icopy(dest, src);
|
|
if (dest->len != 0)
|
|
dest->sgn = !dest->sgn;
|
|
return dest;
|
|
}
|
|
|
|
#if defined(__GNUG__) && !defined(_G_NO_NRV)
|
|
|
|
Integer sqrt(const Integer& x) return r(x)
|
|
{
|
|
int s = sign(x);
|
|
if (s < 0) x.error("Attempted square root of negative Integer");
|
|
if (s != 0)
|
|
{
|
|
r >>= (lg(x) / 2); // get close
|
|
Integer q;
|
|
div(x, r, q);
|
|
while (q < r)
|
|
{
|
|
r += q;
|
|
r >>= 1;
|
|
div(x, r, q);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
Integer lcm(const Integer& x, const Integer& y) return r
|
|
{
|
|
if (!x.initialized() || !y.initialized())
|
|
x.error("operation on uninitialized Integer");
|
|
Integer g;
|
|
if (sign(x) == 0 || sign(y) == 0)
|
|
g = 1;
|
|
else
|
|
g = gcd(x, y);
|
|
div(x, g, r);
|
|
mul(r, y, r);
|
|
}
|
|
|
|
#else
|
|
Integer sqrt(const Integer& x)
|
|
{
|
|
Integer r(x);
|
|
int s = sign(x);
|
|
if (s < 0) x.error("Attempted square root of negative Integer");
|
|
if (s != 0)
|
|
{
|
|
r >>= (lg(x) / 2); // get close
|
|
Integer q;
|
|
div(x, r, q);
|
|
while (q < r)
|
|
{
|
|
r += q;
|
|
r >>= 1;
|
|
div(x, r, q);
|
|
}
|
|
}
|
|
return r;
|
|
}
|
|
|
|
Integer lcm(const Integer& x, const Integer& y)
|
|
{
|
|
Integer r;
|
|
if (!x.initialized() || !y.initialized())
|
|
x.error("operation on uninitialized Integer");
|
|
Integer g;
|
|
if (sign(x) == 0 || sign(y) == 0)
|
|
g = 1;
|
|
else
|
|
g = gcd(x, y);
|
|
div(x, g, r);
|
|
mul(r, y, r);
|
|
return r;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
IntRep* atoIntRep(const char* s, int base)
|
|
{
|
|
int sl = strlen(s);
|
|
IntRep* r = Icalloc(0, sl * (lg(base) + 1) / I_SHIFT + 1);
|
|
if (s != 0)
|
|
{
|
|
char sgn;
|
|
while (isspace(*s)) ++s;
|
|
if (*s == '-')
|
|
{
|
|
sgn = I_NEGATIVE;
|
|
s++;
|
|
}
|
|
else if (*s == '+')
|
|
{
|
|
sgn = I_POSITIVE;
|
|
s++;
|
|
}
|
|
else
|
|
sgn = I_POSITIVE;
|
|
for (;;)
|
|
{
|
|
long digit;
|
|
if (*s >= '0' && *s <= '9') digit = *s - '0';
|
|
else if (*s >= 'a' && *s <= 'z') digit = *s - 'a' + 10;
|
|
else if (*s >= 'A' && *s <= 'Z') digit = *s - 'A' + 10;
|
|
else break;
|
|
if (digit >= base) break;
|
|
r = multiply(r, base, r);
|
|
r = add(r, 0, digit, r);
|
|
++s;
|
|
}
|
|
r->sgn = sgn;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
|
|
|
|
extern AllocRing _libgxx_fmtq;
|
|
|
|
char* Itoa(const IntRep* x, int base, int width)
|
|
{
|
|
int fmtlen = (x->len + 1) * I_SHIFT / lg(base) + 4 + width;
|
|
char* fmtbase = (char *) _libgxx_fmtq.alloc(fmtlen);
|
|
char* f = cvtItoa(x, fmtbase, fmtlen, base, 0, width, 0, ' ', 'X', 0);
|
|
return f;
|
|
}
|
|
|
|
ostream& operator << (ostream& s, const Integer& y)
|
|
{
|
|
#ifdef _OLD_STREAMS
|
|
return s << Itoa(y.rep);
|
|
#else
|
|
if (s.opfx())
|
|
{
|
|
int base = (s.flags() & ios::oct) ? 8 : (s.flags() & ios::hex) ? 16 : 10;
|
|
int width = s.width();
|
|
y.printon(s, base, width);
|
|
}
|
|
return s;
|
|
#endif
|
|
}
|
|
|
|
void Integer::printon(ostream& s, int base /* =10 */, int width /* =0 */) const
|
|
{
|
|
int align_right = !(s.flags() & ios::left);
|
|
int showpos = s.flags() & ios::showpos;
|
|
int showbase = s.flags() & ios::showbase;
|
|
char fillchar = s.fill();
|
|
char Xcase = (s.flags() & ios::uppercase)? 'X' : 'x';
|
|
const IntRep* x = rep;
|
|
int fmtlen = (x->len + 1) * I_SHIFT / lg(base) + 4 + width;
|
|
char* fmtbase = new char[fmtlen];
|
|
char* f = cvtItoa(x, fmtbase, fmtlen, base, showbase, width, align_right,
|
|
fillchar, Xcase, showpos);
|
|
s.write(f, fmtlen);
|
|
delete fmtbase;
|
|
}
|
|
|
|
char* cvtItoa(const IntRep* x, char* fmt, int& fmtlen, int base, int showbase,
|
|
int width, int align_right, char fillchar, char Xcase,
|
|
int showpos)
|
|
{
|
|
char* e = fmt + fmtlen - 1;
|
|
char* s = e;
|
|
*--s = 0;
|
|
|
|
if (x->len == 0)
|
|
*--s = '0';
|
|
else
|
|
{
|
|
IntRep* z = Icopy(0, x);
|
|
|
|
// split division by base into two parts:
|
|
// first divide by biggest power of base that fits in an unsigned short,
|
|
// then use straight signed div/mods from there.
|
|
|
|
// find power
|
|
int bpower = 1;
|
|
unsigned short b = base;
|
|
unsigned short maxb = I_MAXNUM / base;
|
|
while (b < maxb)
|
|
{
|
|
b *= base;
|
|
++bpower;
|
|
}
|
|
for(;;)
|
|
{
|
|
int rem = unscale(z->s, z->len, b, z->s);
|
|
Icheck(z);
|
|
if (z->len == 0)
|
|
{
|
|
while (rem != 0)
|
|
{
|
|
char ch = rem % base;
|
|
rem /= base;
|
|
if (ch >= 10)
|
|
ch += 'a' - 10;
|
|
else
|
|
ch += '0';
|
|
*--s = ch;
|
|
}
|
|
if (!STATIC_IntRep(z)) delete z;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < bpower; ++i)
|
|
{
|
|
char ch = rem % base;
|
|
rem /= base;
|
|
if (ch >= 10)
|
|
ch += 'a' - 10;
|
|
else
|
|
ch += '0';
|
|
*--s = ch;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (base == 8 && showbase)
|
|
*--s = '0';
|
|
else if (base == 16 && showbase)
|
|
{
|
|
*--s = Xcase;
|
|
*--s = '0';
|
|
}
|
|
if (x->sgn == I_NEGATIVE) *--s = '-';
|
|
else if (showpos) *--s = '+';
|
|
int w = e - s - 1;
|
|
if (!align_right || w >= width)
|
|
{
|
|
while (w++ < width)
|
|
*--s = fillchar;
|
|
fmtlen = e - s - 1;
|
|
return s;
|
|
}
|
|
else
|
|
{
|
|
char* p = fmt;
|
|
for (char* t = s; *t != 0; ++t, ++p) *p = *t;
|
|
while (w++ < width) *p++ = fillchar;
|
|
*p = 0;
|
|
fmtlen = p - fmt;
|
|
return fmt;
|
|
}
|
|
}
|
|
|
|
char* dec(const Integer& x, int width)
|
|
{
|
|
return Itoa(x, 10, width);
|
|
}
|
|
|
|
char* oct(const Integer& x, int width)
|
|
{
|
|
return Itoa(x, 8, width);
|
|
}
|
|
|
|
char* hex(const Integer& x, int width)
|
|
{
|
|
return Itoa(x, 16, width);
|
|
}
|
|
|
|
istream& operator >> (istream& stream, Integer& val)
|
|
{
|
|
if (!stream.ipfx0())
|
|
return stream;
|
|
int sign = ' ';
|
|
register streambuf* sb = stream.rdbuf();
|
|
int base = 10;
|
|
int ndigits = 0;
|
|
register int ch = sb->sbumpc();
|
|
while (ch != EOF && isspace(ch))
|
|
ch = sb->sbumpc();
|
|
if (ch == '+' || ch == '-')
|
|
{
|
|
sign = ch;
|
|
ch = sb->sbumpc();
|
|
while (ch != EOF && isspace(ch))
|
|
ch = sb->sbumpc();
|
|
}
|
|
if (ch == EOF) goto eof_fail;
|
|
if (!(stream.flags() & ios::basefield))
|
|
{
|
|
if (ch == '0')
|
|
{
|
|
ch = sb->sbumpc();
|
|
if (ch == EOF) { }
|
|
else if (ch == 'x' || ch == 'X')
|
|
{
|
|
base = 16;
|
|
ch = sb->sbumpc();
|
|
if (ch == EOF) goto eof_fail;
|
|
}
|
|
else
|
|
{
|
|
sb->sputbackc(ch);
|
|
base = 8;
|
|
ch = '0';
|
|
}
|
|
}
|
|
}
|
|
else if ((stream.flags() & ios::basefield) == ios::hex)
|
|
base = 16;
|
|
else if ((stream.flags() & ios::basefield) == ios::oct)
|
|
base = 8;
|
|
|
|
val.rep = Icopy_zero(val.rep);
|
|
|
|
for (;;)
|
|
{
|
|
if (ch == EOF)
|
|
break;
|
|
int digit;
|
|
if (ch >= '0' && ch <= '9')
|
|
digit = ch - '0';
|
|
else if (ch >= 'A' && ch <= 'F')
|
|
digit = ch - 'A' + 10;
|
|
else if (ch >= 'a' && ch <= 'f')
|
|
digit = ch - 'a' + 10;
|
|
else
|
|
digit = 999;
|
|
if (digit >= base)
|
|
{
|
|
sb->sputbackc(ch);
|
|
if (ndigits == 0)
|
|
goto fail;
|
|
else
|
|
goto done;
|
|
}
|
|
ndigits++;
|
|
switch (base)
|
|
{
|
|
case 8:
|
|
val <<= 3;
|
|
break;
|
|
case 16:
|
|
val <<= 4;
|
|
break;
|
|
default:
|
|
val *= base;
|
|
break;
|
|
}
|
|
val += digit;
|
|
ch = sb->sbumpc();
|
|
}
|
|
fail:
|
|
stream.set(ios::failbit);
|
|
done:
|
|
if (sign == '-')
|
|
val.negate();
|
|
return stream;
|
|
eof_fail:
|
|
stream.set(ios::failbit|ios::eofbit);
|
|
return stream;
|
|
}
|
|
|
|
int Integer::OK() const
|
|
{
|
|
if (rep != 0)
|
|
{
|
|
int l = rep->len;
|
|
int s = rep->sgn;
|
|
int v = l <= rep->sz || STATIC_IntRep(rep); // length within bounds
|
|
v &= s == 0 || s == 1; // legal sign
|
|
Icheck(rep); // and correctly adjusted
|
|
v &= rep->len == l;
|
|
v &= rep->sgn == s;
|
|
if (v)
|
|
return v;
|
|
}
|
|
error("invariant failure");
|
|
return 0;
|
|
}
|
|
|
|
void Integer::error(const char* msg) const
|
|
{
|
|
(*lib_error_handler)("Integer", msg);
|
|
}
|
|
|