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.
Sizes of shifts for multiple-precision arithmetic.
These should not be changed unless Integer representation
as unsigned shorts is changed in the implementation files.
#define I_SHIFT (sizeof(short) * CHAR_BIT)
#define I_RADIX ((unsigned long)(1L << I_SHIFT))
#define I_MAXNUM ((unsigned long)((I_RADIX - 1)))
#define I_MINNUM ((unsigned long)(I_RADIX >> 1))
/* All routines assume SHORT_PER_LONG > 1 */
#define SHORT_PER_LONG ((unsigned)(((sizeof(long) + sizeof(short) - 1) / sizeof(short))))
#define CHAR_PER_LONG ((unsigned)sizeof(long))
minimum and maximum sizes for an IntRep
#define MINIntRep_SIZE 16
#define MAXIntRep_SIZE I_MAXNUM
#ifndef MALLOC_MIN_OVERHEAD
#define MALLOC_MIN_OVERHEAD 4
IntRep _ZeroRep
= {1, 0, 1, {0}};
IntRep _OneRep
= {1, 0, 1, {1}};
IntRep _MinusOneRep
= {1, 0, 0, {1}};
// utilities to extract and transfer bits
inline static unsigned short extract(unsigned long x
)
// 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
)
// compare two equal-length reps
inline static int docmp(const unsigned short* x
, const unsigned short* y
, int l
)
const unsigned short* xs
= &(x
[l
]);
const unsigned short* ys
= &(y
[l
]);
while (l
-- > 0 && (diff
= (*--xs
) - (*--ys
)) == 0);
// 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
)
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;
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
)
(*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) +
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);
// allocate: use the bits in src if non-null, clear the rest
IntRep
* Ialloc(IntRep
* old
, const unsigned short* src
, int srclen
, int newsgn
,
if (old
== 0 || newlen
> old
->sz
)
scpy(src
, rep
->s
, srclen
);
Iclear_from(rep
, srclen
);
if (old
!= rep
&& old
!= 0 && !STATIC_IntRep(old
)) delete old
;
IntRep
* Icalloc(IntRep
* old
, int newlen
)
if (old
== 0 || newlen
> old
->sz
)
if (old
!= 0 && !STATIC_IntRep(old
)) delete old
;
IntRep
* Iresize(IntRep
* old
, int newlen
)
scpy(old
->s
, rep
->s
, oldlen
);
if (!STATIC_IntRep(old
)) delete old
;
Iclear_from(rep
, oldlen
);
// same, for straight copy
IntRep
* Icopy(IntRep
* old
, const IntRep
* src
)
if (old
== src
) return old
;
if (old
== 0 || newlen
> old
->sz
)
if (old
!= 0 && !STATIC_IntRep(old
)) delete old
;
scpy(src
->s
, rep
->s
, newlen
);
// allocate & copy space for a long
IntRep
* Icopy_long(IntRep
* old
, long x
)
IntRep
* rep
= Icopy_ulong(old
, newsgn
? x
: -x
);
IntRep
* Icopy_ulong(IntRep
* old
, unsigned long x
)
unsigned short src
[SHORT_PER_LONG
];
unsigned short srclen
= 0;
src
[srclen
++] = extract(x
);
if (old
== 0 || srclen
> old
->sz
)
if (old
!= 0 && !STATIC_IntRep(old
)) delete old
;
scpy(src
, rep
->s
, srclen
);
// special case for zero -- it's worth it!
IntRep
* Icopy_zero(IntRep
* old
)
if (old
== 0 || STATIC_IntRep(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
;
// 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 ((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
)
return (rep
->sgn
== I_POSITIVE
)? a
: -((long)a
);
unsigned long a
= rep
->s
[SHORT_PER_LONG
- 1];
return (rep
->sgn
== I_POSITIVE
) ? LONG_MAX
: LONG_MIN
;
a
= up(a
) | rep
->s
[SHORT_PER_LONG
- 2];
for (int i
= SHORT_PER_LONG
- 3; i
>= 0; --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
;
else if (l
> SHORT_PER_LONG
)
else if ((unsigned)(rep
->s
[SHORT_PER_LONG
- 1]) < (unsigned)(I_MINNUM
))
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
)
double Itodouble(const IntRep
* rep
)
double bound
= DBL_MAX
/ 2.0;
for (int i
= rep
->len
- 1; i
>= 0; --i
)
unsigned short a
= I_RADIX
>> 1;
return (rep
->sgn
== I_NEGATIVE
) ? -HUGE_VAL
: HUGE_VAL
;
if (rep
->sgn
== I_NEGATIVE
)
// see whether op double() will work-
// have to actually try it in order to find out
// since otherwise might trigger fp exception
int Iisdouble(const IntRep
* rep
)
double bound
= DBL_MAX
/ 2.0;
for (int i
= rep
->len
- 1; i
>= 0; --i
)
unsigned short a
= I_RADIX
>> 1;
if (d
> bound
|| (d
== bound
&& (i
> 0 || (rep
->s
[i
] & a
))))
// real division of num / den
double ratio(const Integer
& num
, const Integer
& den
)
double d1
= q
.as_double();
if (d1
>= DBL_MAX
|| d1
<= -DBL_MAX
|| sign(r
) == 0)
else // use as much precision as available for fractional part
for (int i
= den
.rep
->len
- 1; i
>= 0 && cont
; --i
)
unsigned short a
= I_RADIX
>> 1;
if (d2
+ 1.0 == d2
) // out of precision when we get here
int compare(const IntRep
* x
, const IntRep
* y
)
int diff
= x
->sgn
- y
->sgn
;
diff
= docmp(x
->s
, y
->s
, x
->len
);
if (x
->sgn
== I_NEGATIVE
)
int ucompare(const IntRep
* x
, const IntRep
* y
)
int diff
= x
->len
- y
->len
;
const unsigned short* xs
= &(x
->s
[l
]);
const unsigned short* ys
= &(y
->s
[l
]);
while (l
-- > 0 && (diff
= (*--xs
) - (*--ys
)) == 0);
int compare(const IntRep
* x
, long y
)
else if (xsgn
== I_NEGATIVE
)
unsigned long uy
= (ysgn
)? y
: -y
;
diff
= xl
- SHORT_PER_LONG
;
unsigned short tmp
[SHORT_PER_LONG
];
diff
= docmp(x
->s
, tmp
, xl
);
int ucompare(const IntRep
* x
, long y
)
unsigned long uy
= (y
>= 0)? y
: -y
;
int diff
= xl
- SHORT_PER_LONG
;
unsigned short tmp
[SHORT_PER_LONG
];
diff
= docmp(x
->s
, tmp
, xl
);
IntRep
* add(const IntRep
* x
, int negatex
,
const IntRep
* y
, int negatey
, IntRep
* r
)
int xsgn
= (negatex
&& xl
!= 0) ? !x
->sgn
: x
->sgn
;
int ysgn
= (negatey
&& yl
!= 0) ? !y
->sgn
: y
->sgn
;
r
= Ialloc(r
, x
->s
, xl
, xsgn
, xl
);
r
= Ialloc(r
, y
->s
, yl
, ysgn
, yl
);
r
= Iresize(r
, calc_len(xl
, yl
, 1));
r
= Icalloc(r
, calc_len(xl
, yl
, 1));
unsigned short* rs
= r
->s
;
const unsigned short* as
;
const unsigned short* bs
;
const unsigned short* topa
;
const unsigned short* topb
;
as
= (xrsame
)? r
->s
: x
->s
;
bs
= (yrsame
)? r
->s
: y
->s
;
bs
= (xrsame
)? r
->s
: x
->s
;
as
= (yrsame
)? r
->s
: y
->s
;
sum
+= (unsigned long)(*as
++) + (unsigned long)(*bs
++);
while (sum
!= 0 && as
< topa
)
sum
+= (unsigned long)(*as
++);
int comp
= ucompare(x
, y
);
r
= Iresize(r
, calc_len(xl
, yl
, 0));
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
;
as
= (xrsame
)? r
->s
: x
->s
;
bs
= (yrsame
)? r
->s
: y
->s
;
bs
= (xrsame
)? r
->s
: x
->s
;
as
= (yrsame
)? r
->s
: y
->s
;
hi
+= (unsigned long)(*as
++) + I_MAXNUM
- (unsigned long)(*bs
++);
while (hi
== 0 && as
< topa
)
hi
= (unsigned long)(*as
++) + I_MAXNUM
;
IntRep
* add(const IntRep
* x
, int negatex
, long y
, IntRep
* r
)
int xsgn
= (negatex
&& xl
!= 0) ? !x
->sgn
: x
->sgn
;
unsigned long uy
= (ysgn
)? y
: -y
;
r
= Ialloc(r
, x
->s
, xl
, xsgn
, xl
);
r
= Iresize(r
, calc_len(xl
, SHORT_PER_LONG
, 1));
r
= Icalloc(r
, calc_len(xl
, SHORT_PER_LONG
, 1));
unsigned short* rs
= r
->s
;
const unsigned short* as
= (xrsame
)? r
->s
: x
->s
;
const unsigned short* topa
= &(as
[xl
]);
while (as
< topa
&& uy
!= 0)
unsigned long u
= extract(uy
);
sum
+= (unsigned long)(*as
++) + u
;
while (sum
!= 0 && as
< topa
)
sum
+= (unsigned long)(*as
++);
unsigned short tmp
[SHORT_PER_LONG
];
comp
= docmp(x
->s
, tmp
, yl
);
r
= Iresize(r
, calc_len(xl
, yl
, 0));
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
;
as
= (xrsame
)? r
->s
: x
->s
;
bs
= (xrsame
)? r
->s
: x
->s
;
hi
+= (unsigned long)(*as
++) + I_MAXNUM
- (unsigned long)(*bs
++);
while (hi
== 0 && as
< topa
)
hi
= (unsigned long)(*as
++) + I_MAXNUM
;
IntRep
* multiply(const IntRep
* x
, const IntRep
* y
, IntRep
* r
)
int rsgn
= x
->sgn
== y
->sgn
;
else if (xl
== 1 && x
->s
[0] == 1)
else if (yl
== 1 && y
->s
[0] == 1)
else if (!(xysame
&& xrsame
))
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
;
unsigned long ai
= (unsigned long)(*as
--);
unsigned short* rs
= currentr
--;
const unsigned short* bs
= botb
;
sum
+= ai
* (unsigned long)(*bs
++) + (unsigned long)(*rs
);
while (sum
!= 0 && rs
< topr
)
sum
+= (unsigned long)(*rs
);
else // x, y, and r same; compute over diagonals
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
;
const unsigned short* h
= hia
;
const unsigned short* l
= loa
;
unsigned long prod
= (unsigned long)(*h
) * (unsigned long)(*l
);
unsigned long sum
= prod
+ (unsigned long)(*rt
);
while (sum
!= 0 && rt
< topr
)
sum
+= (unsigned long)(*rt
);
sum
= prod
+ (unsigned long)(*rt
);
while (sum
!= 0 && rt
< topr
)
sum
+= (unsigned long)(*rt
);
prod
= (unsigned long)(*h
) * (unsigned long)(*l
);
IntRep
* multiply(const IntRep
* x
, long y
, IntRep
* r
)
int rsgn
= x
->sgn
== ysgn
;
unsigned long uy
= (ysgn
)? y
: -y
;
unsigned short tmp
[SHORT_PER_LONG
];
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
;
unsigned long ai
= (unsigned long)(*as
--);
unsigned short* rs
= currentr
--;
const unsigned short* bs
= botb
;
sum
+= ai
* (unsigned long)(*bs
++) + (unsigned long)(*rs
);
while (sum
!= 0 && rs
< topr
)
sum
+= (unsigned long)(*rs
);
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];
unsigned short qhat
; // guess q
unsigned long lr
= up((unsigned long)rs
[i
]) | rs
[i
-1];
for(;;) // adjust q, use docmp to avoid overflow problems
unsigned long prod
= (unsigned long)d2
* (unsigned long)qhat
;
prod
= down(prod
) + (unsigned long)d1
* (unsigned long)qhat
;
ts
[2] = extract(down(prod
));
if (docmp(ts
, &(rs
[i
-2]), 3) > 0)
const unsigned short* yt
= ys
;
unsigned short* rt
= &(rs
[l
]);
prod
= (unsigned long)qhat
* (unsigned long)(*yt
++) + down(prod
);
hi
+= (unsigned long)(*rt
) + I_MAXNUM
- (unsigned long)(extract(prod
));
hi
+= (unsigned long)(*rt
) + I_MAXNUM
- (unsigned long)(down(prod
));
hi
= (unsigned long)(*rt
) + (unsigned long)(*yt
++) + down(hi
);
// 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* botq
= q
;
unsigned short* qs
= &(botq
[xl
- 1]);
const unsigned short* xs
= &(x
[xl
- 1]);
unsigned long u
= rem
/ y
;
else // same loop, a bit faster if just need rem
const unsigned short* botx
= x
;
const unsigned short* xs
= &(botx
[xl
- 1]);
unsigned long u
= rem
/ y
;
IntRep
* div(const IntRep
* x
, const IntRep
* y
, IntRep
* q
)
if (yl
== 0) (*lib_error_handler
)("Integer", "attempted division by zero");
int comp
= ucompare(x
, y
);
int samesign
= xsgn
== ysgn
;
q
= Icopy_one(q
, samesign
);
unscale(q
->s
, q
->len
, y
->s
[0], q
->s
);
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
);
do_divide(r
->s
, yy
->s
, yl
, q
->s
, ql
);
if (yy
!= y
&& !STATIC_IntRep(yy
)) delete yy
;
if (!STATIC_IntRep(r
)) delete r
;
IntRep
* div(const IntRep
* x
, long y
, IntRep
* q
)
if (y
== 0) (*lib_error_handler
)("Integer", "attempted division by zero");
unsigned short ys
[SHORT_PER_LONG
];
if (comp
== 0) comp
= docmp(x
->s
, ys
, xl
);
int samesign
= xsgn
== ysgn
;
q
= Icopy_one(q
, samesign
);
unscale(q
->s
, q
->len
, ys
[0], q
->s
);
unsigned short prescale
= (I_RADIX
/ (1 + ys
[yl
- 1]));
unsigned long prod
= (unsigned long)prescale
* (unsigned long)ys
[0];
prod
= down(prod
) + (unsigned long)prescale
* (unsigned long)ys
[1];
r
= multiply(x
, ((long)prescale
& I_MAXNUM
), r
);
do_divide(r
->s
, ys
, yl
, q
->s
, ql
);
if (!STATIC_IntRep(r
)) delete r
;
void divide(const Integer
& Ix
, long y
, Integer
& Iq
, long& rem
)
const IntRep
* x
= Ix
.rep
;
if (y
== 0) (*lib_error_handler
)("Integer", "attempted division by zero");
unsigned short ys
[SHORT_PER_LONG
];
if (comp
== 0) comp
= docmp(x
->s
, ys
, xl
);
int samesign
= xsgn
== ysgn
;
q
= Icopy_one(q
, samesign
);
rem
= unscale(q
->s
, q
->len
, ys
[0], q
->s
);
unsigned short prescale
= (I_RADIX
/ (1 + ys
[yl
- 1]));
unsigned long prod
= (unsigned long)prescale
* (unsigned long)ys
[0];
prod
= down(prod
) + (unsigned long)prescale
* (unsigned long)ys
[1];
r
= multiply(x
, ((long)prescale
& I_MAXNUM
), r
);
do_divide(r
->s
, ys
, yl
, q
->s
, ql
);
unscale(r
->s
, r
->len
, prescale
, r
->s
);
if (!STATIC_IntRep(r
)) delete r
;
if (xsgn
== I_NEGATIVE
) rem
= -rem
;
void divide(const Integer
& Ix
, const Integer
& Iy
, Integer
& Iq
, Integer
& Ir
)
const IntRep
* x
= Ix
.rep
;
const IntRep
* y
= Iy
.rep
;
(*lib_error_handler
)("Integer", "attempted division by zero");
int comp
= ucompare(x
, y
);
int samesign
= xsgn
== ysgn
;
q
= Icopy_one(q
, samesign
);
int rem
= unscale(q
->s
, q
->len
, y
->s
[0], q
->s
);
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
);
do_divide(r
->s
, yy
->s
, yl
, q
->s
, ql
);
if (yy
!= y
&& !STATIC_IntRep(yy
)) delete yy
;
unscale(r
->s
, r
->len
, prescale
, r
->s
);
IntRep
* mod(const IntRep
* x
, const IntRep
* y
, IntRep
* r
)
if (yl
== 0) (*lib_error_handler
)("Integer", "attempted division by zero");
int comp
= ucompare(x
, y
);
int rem
= unscale(x
->s
, xl
, y
->s
[0], 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
);
do_divide(r
->s
, yy
->s
, yl
, 0, xl
- yl
+ 1);
if (yy
!= y
&& !STATIC_IntRep(yy
)) delete yy
;
unscale(r
->s
, r
->len
, prescale
, r
->s
);
IntRep
* mod(const IntRep
* x
, long y
, IntRep
* r
)
if (y
== 0) (*lib_error_handler
)("Integer", "attempted division by zero");
unsigned short ys
[SHORT_PER_LONG
];
if (comp
== 0) comp
= docmp(x
->s
, ys
, xl
);
int rem
= unscale(x
->s
, xl
, ys
[0], 0);
unsigned short prescale
= (I_RADIX
/ (1 + ys
[yl
- 1]));
unsigned long prod
= (unsigned long)prescale
* (unsigned long)ys
[0];
prod
= down(prod
) + (unsigned long)prescale
* (unsigned long)ys
[1];
r
= multiply(x
, ((long)prescale
& I_MAXNUM
), r
);
do_divide(r
->s
, ys
, yl
, 0, xl
- yl
+ 1);
unscale(r
->s
, r
->len
, prescale
, r
->s
);
IntRep
* lshift(const IntRep
* x
, long y
, IntRep
* r
)
long ay
= (y
< 0)? -y
: y
;
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]);
a
= up(a
) | ((unsigned long)(*xs
--) << sw
);
*rs
-- = extract(down(a
));
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
;
a
|= (unsigned long)(*xs
++) << rw
;
if (xrsame
) topr
= (unsigned short*)topx
;
IntRep
* lshift(const IntRep
* x
, const IntRep
* yy
, int negatey
, IntRep
* r
)
IntRep
* bitop(const IntRep
* x
, const IntRep
* y
, IntRep
* r
, char op
)
r
= Iresize(r
, calc_len(xl
, yl
, 0));
r
= Icalloc(r
, calc_len(xl
, yl
, 0));
unsigned short* rs
= r
->s
;
unsigned short* topr
= &(rs
[r
->len
]);
const unsigned short* as
;
const unsigned short* bs
;
const unsigned short* topb
;
as
= (xrsame
)? rs
: x
->s
;
bs
= (yrsame
)? rs
: y
->s
;
bs
= (xrsame
)? rs
: x
->s
;
as
= (yrsame
)? rs
: y
->s
;
while (bs
< topb
) *rs
++ = *as
++ & *bs
++;
while (rs
< topr
) *rs
++ = 0;
while (bs
< topb
) *rs
++ = *as
++ | *bs
++;
while (rs
< topr
) *rs
++ = *as
++;
while (bs
< topb
) *rs
++ = *as
++ ^ *bs
++;
while (rs
< topr
) *rs
++ = *as
++;
IntRep
* bitop(const IntRep
* x
, long y
, IntRep
* r
, char op
)
unsigned short tmp
[SHORT_PER_LONG
];
r
= Iresize(r
, calc_len(xl
, yl
, 0));
r
= Icalloc(r
, calc_len(xl
, yl
, 0));
unsigned short* rs
= r
->s
;
unsigned short* topr
= &(rs
[r
->len
]);
const unsigned short* as
;
const unsigned short* bs
;
const unsigned short* topb
;
as
= (xrsame
)? rs
: x
->s
;
bs
= (xrsame
)? rs
: x
->s
;
while (bs
< topb
) *rs
++ = *as
++ & *bs
++;
while (rs
< topr
) *rs
++ = 0;
while (bs
< topb
) *rs
++ = *as
++ | *bs
++;
while (rs
< topr
) *rs
++ = *as
++;
while (bs
< topb
) *rs
++ = *as
++ ^ *bs
++;
while (rs
< topr
) *rs
++ = *as
++;
IntRep
* compl(const IntRep
* src
, IntRep
* r
)
unsigned short* s
= r
->s
;
unsigned short* top
= &(s
[r
->len
- 1]);
unsigned short cmp
= ~(*s
);
void (setbit
)(Integer
& x
, long b
)
int bw
= (unsigned long)b
/ I_SHIFT
;
int sw
= (unsigned long)b
% I_SHIFT
;
int xl
= x
.rep
? x
.rep
->len
: 0;
x
.rep
= Iresize(x
.rep
, calc_len(xl
, bw
+1, 0));
x
.rep
->s
[bw
] |= (1 << sw
);
void clearbit(Integer
& x
, long b
)
int bw
= (unsigned long)b
/ I_SHIFT
;
int sw
= (unsigned long)b
% I_SHIFT
;
x
.rep
->s
[bw
] &= ~(1 << sw
);
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);
// 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
)
return Ialloc(0, x
->s
, ul
, I_POSITIVE
, ul
);
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
int l
= (ul
<= vl
)? ul
: vl
;
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
)
t
= Ialloc(0, v
->s
, v
->len
, !v
->sgn
, v
->len
);
t
= Ialloc(0, u
->s
, u
->len
, u
->sgn
, u
->len
);
long s
= 0; // shift t until odd
for (i
= 0; i
< tl
&& cont
; ++i
)
unsigned long a
= t
->s
[i
];
for (int j
= 0; j
< I_SHIFT
; ++j
)
if (s
!= 0) t
= lshift(t
, -s
, t
);
if (t
->sgn
== I_POSITIVE
)
v
= Ialloc(v
, t
->s
, t
->len
, !t
->sgn
, t
->len
);
if (!STATIC_IntRep(t
)) delete t
;
if (!STATIC_IntRep(v
)) delete v
;
if (k
!= 0) u
= lshift(u
, k
, u
);
long l
= (xl
- 1) * I_SHIFT
- 1;
unsigned short a
= x
->s
[xl
-1];
IntRep
* power(const IntRep
* x
, long y
, IntRep
* r
)
if (x
->sgn
== I_POSITIVE
|| (!(y
& 1)))
if (y
== 0 || (xl
== 1 && x
->s
[0] == 1))
else if (xl
== 0 || y
< 0)
else if (y
== 1 || y
== -1)
int maxsize
= ((lg(x
) + 1) * y
) / I_SHIFT
+ 2; // pre-allocate space
IntRep
* b
= Ialloc(0, x
->s
, xl
, I_POSITIVE
, maxsize
);
r
= Icopy_one(r
, I_POSITIVE
);
if (!STATIC_IntRep(b
)) delete b
;
IntRep
* abs(const IntRep
* src
, IntRep
* dest
)
IntRep
* negate(const IntRep
* src
, IntRep
* dest
)
#if defined(__GNUG__) && !defined(NO_NRV)
Integer
sqrt(const Integer
& x
) return r(x
)
if (s
< 0) x
.error("Attempted square root of negative Integer");
r
>>= (lg(x
) / 2); // get close
Integer
lcm(const Integer
& x
, const Integer
& y
) return r
if (!x
.initialized() || !y
.initialized())
x
.error("operation on uninitialized Integer");
if (sign(x
) == 0 || sign(y
) == 0)
Integer
sqrt(const Integer
& x
)
if (s
< 0) x
.error("Attempted square root of negative Integer");
r
>>= (lg(x
) / 2); // get close
Integer
lcm(const Integer
& x
, const Integer
& y
)
if (!x
.initialized() || !y
.initialized())
x
.error("operation on uninitialized Integer");
if (sign(x
) == 0 || sign(y
) == 0)
IntRep
* atoIntRep(const char* s
, int base
)
IntRep
* r
= Icalloc(0, sl
* (lg(base
) + 1) / I_SHIFT
+ 1);
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;
if (digit
>= base
) break;
r
= multiply(r
, base
, 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);
ostream
& operator << (ostream
& s
, const Integer
& y
)
int base
= (s
.flags() & ios::oct
) ? 8 : (s
.flags() & ios::hex
) ? 16 : 10;
y
.printon(s
, base
, width
);
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';
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
);
char* cvtItoa(const IntRep
* x
, char* fmt
, int& fmtlen
, int base
, int showbase
,
int width
, int align_right
, char fillchar
, char Xcase
,
char* e
= fmt
+ fmtlen
- 1;
// 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.
unsigned short maxb
= I_MAXNUM
/ base
;
int rem
= unscale(z
->s
, z
->len
, b
, z
->s
);
if (!STATIC_IntRep(z
)) delete z
;
for (int i
= 0; i
< bpower
; ++i
)
if (base
== 8 && showbase
)
else if (base
== 16 && showbase
)
if (x
->sgn
== I_NEGATIVE
) *--s
= '-';
else if (showpos
) *--s
= '+';
if (!align_right
|| w
>= width
)
for (char* t
= s
; *t
!= 0; ++t
, ++p
) *p
= *t
;
while (w
++ < width
) *p
++ = fillchar
;
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
& s
, Integer
& y
)
s
.clear(ios::failbit
|s
.rdstate());
s
.clear(ios::failbit
|s
.rdstate());
int know_base
= s
.flags() & (ios::oct
| ios::hex
| ios::dec
);
int base
= (s
.flags() & ios::oct
) ? 8 : (s
.flags() & ios::hex
) ? 16 : 10;
y
.rep
= Icopy_zero(y
.rep
);
else if (!know_base
& !got_one
&& ch
== '0')
else if (!know_base
& !got_one
&& base
== 8 && (ch
== 'X' || ch
== 'x'))
if (ch
>= '0' && ch
<= '7')
if (ch
>= '0' && ch
<= '9')
else if (ch
>= 'A' && ch
<= 'F')
else if (ch
>= 'a' && ch
<= 'f')
if (ch
>= '0' && ch
<= '9')
abort(); // can't happen for now
s
.clear(ios::failbit
|s
.rdstate());
int v
= l
<= rep
->sz
|| STATIC_IntRep(rep
); // length within bounds
v
&= s
== 0 || s
== 1; // legal sign
Icheck(rep
); // and correctly adjusted
error("invariant failure");
void Integer::error(const char* msg
) const
(*lib_error_handler
)("Integer", msg
);