Files
secondo/include/BigInt.h
2026-01-23 17:03:45 +08:00

1184 lines
24 KiB
C++

/*
----
This file is part of SECONDO.
Copyright (C) 2004, University in Hagen, Department of Computer Science,
Database Systems for New Applications.
SECONDO 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 of the License, or
(at your option) any later version.
SECONDO 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 SECONDO; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
----
//paragraph [3] abstract: [\begin{abstract}] [\end{abstract}]
//[<<] [\textless\textless]
//[title] [\title{The BigInt class}\author{Thomas Behr}\maketitle]
//[content] [\tableofcontents]
//[|] [\ensuremath{\mid}]
[title]
[content]
[3] This class provides a integer with the usual operations.
The size of this integer can be selected by the template
argument size. The actual size will be 4[*]size +1 bytes.
One byte is reserved for the signum. All other bytes are used
for storing the absolute value of this number.
*/
#ifndef BIGINT_H
#define BIGINT_H
/*
1 Preparations
1.1 Includes
For overloading the operator [<<] the ostream class is required.
So, we have to include the iostream header.
*/
#include<iostream>
#include <assert.h>
/*
1.2 Some Forward declarations
*/
template<unsigned int size> class BigInt;
template<unsigned int size> std::ostream&
operator<<(std::ostream &o,const BigInt<size>& i);
const unsigned int numberOfBits = (sizeof(unsigned long))*8;
const unsigned int numberOfBitsM1 = numberOfBits-1;
/*
2 Declaration and Definition of the class
*/
template<unsigned int size> class BigInt{
/*
2.1 Private Members
This sections conatins all member which should be not used
by external classes.
2.1.1 The data for representation
*/
private:
/*
~signum~
This boolean value describes the signum of this number.
When the value is false, the number is negative - otherwise
the number is positive.
*/
bool signum;
/*
~value~
This array contains the representation of the absolute value of this number.
*/
unsigned long value[size];
/*
2.1.2 Private Functions
*/
/*
~Add~
This function adds the value arguments. The summands are given as
s1 and s2 respectively. The result is stored in sum. This function works
also when an argument is equals to the result, e.g. Add(v,v,v,overflow)
will double the value of v.
*/
static void Add( const unsigned long* s1,
const unsigned long* s2,
unsigned long* sum,
bool& overflow){
unsigned char c1,c2,c3,res;
// go thought all value
c3 = 0; // no overflow
unsigned long pos;
// first, we initialize sum with 0
for(unsigned int i=0; i<size ; i++){
for(unsigned int j=0;j<numberOfBits;j++){
pos = 1UL << j;
c1 = ((s1[i] & pos) !=0)?1:0;
c2 = ((s2[i] & pos) !=0)?1:0;
res = c1+c2+c3;
switch(res){
case 0: c3 = 0; sum[i] = sum[i] & ~pos;break;
case 1: c3 = 0; sum[i] = sum[i] | pos;break;
case 2: c3 = 1; sum[i] = sum[i] & ~pos;break;
case 3: c3 = 1; sum[i] = sum[i] | pos; break;
default: assert(false); // inpossible result
}
}
}
overflow = c3!=0;
}
static int valueof(char c){
return (int)(c-'0');
}
/*
~Complement1~
This function computes the complement of this number, e.g. all bits
(and also the signum) will be inverted.
*/
void Complement1(){
for(unsigned int i=0;i<size;i++){
value[i] = ~value[i];
}
signum = !signum;
}
/*
~Complement2~
This function computes the complement on 2 of this number. This means,
all bits are inverted and after this, a value of 1 is added to this number.
This function is necessary for realizing the ~Minus~ operator.
*/
void Complement2(bool& overflow){
Complement1();
Add(this->value,ONE.value,this->value,overflow);
}
/*
~IsOne~
This function checks whether the bit at position p is set to 1.
*/
bool IsOne(unsigned int p){
unsigned int p1 = p/numberOfBits;
if(p1>=size){ // outside the valid range
return false;
}
unsigned long v = value[p1];
unsigned int pos = p%numberOfBits;
unsigned long bitmask = 1UL << pos;
return (v&bitmask)!=0;
}
/*
~SigPos~
This function checks how many positions are required for writing down the
absolute value of this number without leading zeros. If the value is zero,
also the result will be zero.
*/
unsigned int SigPos()const{
unsigned int result = numberOfBits*size;
bool done = false;
unsigned long pos;
for(int i=size-1; i>=0 && !done ;i--){
if(value[i]==0){
result -= numberOfBits;
}else{
for(int j=(numberOfBitsM1);j>=0;j--){
pos = 1uL << j;
if ( (pos & value[i])==0){
result --;
}else{
return result;;
}
}
}
}
return result;
}
/*
~mul2~
Multiplies the content of work given in decimal system with 2.
The return value specifies whether a overflow is occured.
This function is used in a decimal formatted output of this number.
*/
static bool mul2(unsigned char* work,unsigned int maxsize){
unsigned char last=0;
unsigned char current;
for(unsigned int i=0;i<maxsize;i++){
current=work[i]*2+last;
last = current/10;
work[i] = current%10;
}
return last>0;
}
/*
~plus1~
Adds 1 to the content of work. Work is representing a decimal
number.This function is used for output this number in
decimal format.
*/
static bool plus1(unsigned char* work,unsigned int maxsize){
unsigned char of=1;
unsigned char current;
for(unsigned int i=0;i<maxsize && of>0;i++){
current = work[i]+of;
of = current/10;
work[i] = current%10;
}
return of>0;
}
/*
~write~
This functions writes the content of work (describing a decimal number)
to o. This function is used for output this number in decimal format.
*/
static void write(std::ostream& o, unsigned char* work,
unsigned int maxsize){
bool run = false;
for(int i=maxsize-1;i>=0;i--){
if(work[i]>0){
run = true;
}
if(run){
o << (unsigned int)work[i];
}
}
if(!run)
o << "0";
}
/*
2.2 Public Section
This section contains members and functions useful in
external classes.
*/
public:
/*
2.2.1 Constructors
~Constructor~
This constructor creates a new BigInt instance with value zero.
*/
BigInt(){
ReadFrom(0);
}
/*
~Constructor~
This constructor creates a new BigInt instance with the given value;
*/
BigInt(const long value){
ReadFrom(value);
}
/*
~Constructor~
This constructor reads the value of this instance from the
character array. The array is readed up to length or when an
invalid symbol occurs. The format of the array must be:
* ([+-][ ][|][+-])?[0-9][*].
*/
BigInt(char* content,size_t length){
ReadFrom(content,length);
}
/*
~Constructor~
When this constructor is called, the value of the new instance will be equal
to the value of the argument.
*/
BigInt(const BigInt<size>& arg){
Equalize(arg);
}
/*
2.2.2 Some frequently used constants
*/
/*
~ONE~
This member describes the constant value 1.
*/
const static BigInt<size> ONE;
/*
~ZERO~
This member describes the constant value 0.
*/
const static BigInt<size> ZERO;
/*
~TEN~
This member describes the constant value 10.
*/
const static BigInt<size> TEN;
/*
2.2.3 Public functions
~Equalize~
When this function is called, the value of this bigint is taken from the argument.
*/
void Equalize(const BigInt<size>& arg){
this->signum = arg.signum;
for(unsigned int i=0;i<size;i++){
this->value[i]=arg.value[i];
}
}
/*
~Equals~
The function checks this objects for equality with the argument. A call of this function
is more efficient than the use of ~CompareTo~
*/
bool Equals(const BigInt<size>& arg)const{
if(signum!=arg.signum)
return false;
for(unsigned int i=0;i<size;i++)
if(value[i]!=arg.value[i])
return false;
return true;
}
/*
~IsZero~
This function checks whether the value of this number is zero.
This result of this function is independly of the signum.
*/
bool IsZero(){
for(unsigned int i=0;i<size;i++){
if(value[i]!=0){
return false;
}
}
return true;
}
/*
~ToLong~
This function returns the value of this BigInt as a long value.
The additional argument ~correct~ specifies whether the
long value is able to represent the value of this BigInt.
If not, the result will conatain an undefined value.
*/
long ToLong(bool& correct){
// check whether more than the first part is used
correct = true;
for(unsigned int i=1;i<size;i++){
if(value[i]!=0)
correct = false;
}
// If the highest bit of the first part is used, a long
// value is also too small for representing this value.
if( ((1UL << (numberOfBitsM1)) & value[0]) !=0){
correct = false;
}
// copy the value of the lowest part into a result
unsigned long v = value[0];
long r = 0UL;
unsigned long pos = 1UL << (numberOfBitsM1);
for(unsigned int i=0;i<numberOfBits;i++){
if( (v&pos)>0)
r++;
if(i<(numberOfBitsM1))r=r<<1;
pos = pos >> 1;
}
if(!signum)
r = -1*r;
return r;
}
/*
~Add~
This operator realizes the addition of the arguments.
*/
BigInt<size> Add(const BigInt<size>& summand,bool& overflow)const{
BigInt<size> result(0);
result.Equalize(*this);
result.AddInternal(summand,overflow);
return result;
}
/*
~AddInternal~
The ~AddInternal~ method adds the argument to this instance.
In contrast to the ~Add~ operator, this instance is changed
while this operation.
*/
void AddInternal(const BigInt<size>& summand,bool& overflow){
if(this->signum==summand.signum){
Add(this->value,summand.value,this->value,overflow);
}else{ // different signums
bool of;
this->Complement2(of);
Add(this->value,summand.value,this->value,overflow);
if(!overflow && !of){
this->Complement2(overflow);
this->signum=false;
}else{
this->signum=true;
}
if(!summand.signum){
this->signum = !this->signum;
}
}
}
/*
~MinusInternal~
This function subtract the argument fro this instance.
No result is created, rather the result is stored in
this instance directly.
*/
void MinusInternal(const BigInt<size>& subtrahend, bool& overflow){
this->signum=!this->signum;
AddInternal(subtrahend,overflow);
this->signum=!this->signum;
if(this->IsZero()){
this->signum=true;
}
}
/*
~Minus~
This operator performs the subtraction of the argument from this
instance.
*/
BigInt<size> Minus(const BigInt<size>& subtrahend,bool& overflow)const{
BigInt<size> result(0);
result.Equalize(*this);
result.MinusInternal(subtrahend,overflow);
return result;
}
/*
~Mul~
When calling this function, the result will be the product of
this with the argument. The argument overflow will be true after calling
this function when the size of the numbers is'nt sufficient to hold the
value of the result.
*/
BigInt<size> Mul(const BigInt<size>& factor, bool& overflow)const{
BigInt<size> result(0);
result.Equalize(*this);
result.MulInternal(factor,overflow);
return result;
}
/*
~MulInternal~
This function multiplies this with the argument.
*/
void MulInternal(const BigInt<size>& factor, bool& overflow){
overflow = false;
bool of = false;
int cmp = CompareAbsTo(factor);
BigInt<size> f1,f2;
if(cmp<0){
f1.Equalize(factor);
f2.Equalize(*this);
}else{
f2.Equalize(factor);
f1.Equalize(*this);
}
bool sig = !(factor.signum ^ this->signum);
this->ReadFrom(0);
int num = f2.SigPos();
f1.signum=true;
f2.signum=true;
for(int i=0;i<num;i++){
if(f2.IsOne(i)){
this->AddInternal(f1,of);
if(of)
overflow=true;
}
if(f1.ShiftLeft1() ){
overflow=true;
}
}
this->signum = sig;
}
/*
~Div~
This function performs a division between the this bigint and the argument.
The result of the division is returned. The remainder of this operation
is stored in the coresponding argument.
*/
BigInt<size> Div(const BigInt<size> divisor, BigInt<size>& remainder)const{
int num1 = this->SigPos();
int num2 = divisor.SigPos();
BigInt<size> n1;
n1.Equalize(*this);
BigInt<size> n2;
n2.Equalize(divisor);
BigInt<size> result(0);
if(num1<num2 ){ // this is smaller than the divisor
remainder.Equalize(*this);
return result; // zero at this point
}
if(num2==0){
return result;
}
n1.signum = true; // remove negations
n2.signum = true;
// shift the value of the divisor 'under' the value of this
int dif = num1-num2;
n2.ShiftLeft(dif);
BigInt<size> tmp;
bool of;
for(int i=0;i<=dif;i++){
tmp = n1.Minus(n2,of);
result.ShiftLeft1();
if(tmp.signum || tmp.IsZero()){ //non-negative number
result.AddInternal(ONE,of);
n1.Equalize(tmp);
}
n2.ShiftRight1();
}
remainder.Equalize(n1);
remainder.signum = this->signum;
result.signum=!(this->signum ^ divisor.signum);
return result;
}
/*
~AbsInternal~
Sets the value of this number to its absolute value.
*/
void AbsInternal(){
signum=true;
}
/*
~Abs~
This functions returns the absolute value of this number.
*/
BigInt<size> Abs(){
BigInt<size> result(*this);
result.signum=true;
return result;
}
/*
~CorrectSignum~
This function removes the signum of this number when its value is zero.
*/
void CorrectSignum(){
if(IsZero()){
signum=true;
}
}
/*
~CompareTo~
Compares this with the argument. The result will be:
* -1 : if this number is smaller than the argument
* 0 : if this number is greater than the argument
* 1 : if the value of this object is greater than the argument
Note that this function differs between a negative and a positive
zero. This means, a zero with negative signum is smaller than a
positive zero. The avois this behavior, first call the ~CorrectSignum~
function which removes any signum when the absolute value is zero.
*/
int CompareTo(const BigInt<size> arg)const{
if(!signum && arg.signum){
return -1;
}
if(signum && ! arg.signum){
return 1;
}
int sig = signum?1:-1;
unsigned long pos;
for(int i=size-1;i>=0;i--){
for(int j=(numberOfBitsM1);j>=0;j--){
pos = 1ul<<j;
if( ((value[i]&pos) !=0) && ((arg.value[i]&pos)==0)){
return sig;
}
if( ((value[i]&pos) ==0) && ((arg.value[i]&pos)!=0)){
return -sig;
}
}
}
return 0;
}
/*
~Negate~
This function will invert the signum of this number.
*/
void Negate(){
signum = !signum;
}
/*
~CompareAbsTo~
Compares the values of this integers regardless to the signum.
*/
int CompareAbsTo(const BigInt<size> arg)const{
unsigned long v1,v2;
for(int i=size-1;i>=0;i--){
for(int j=(numberOfBitsM1);j>=0;j--){
v1 = (1UL << j) | value[i];
v2 = (1UL << j) | arg.value[i];
if(v1>v2)
return 1;
if(v2>v1)
return -1;
}
}
return 0;
}
/*
~ShiftLeft1~
Shifts this value at 1 position to left filling with zeros.
The result is true when an overflow is occured. This function
is a specialized version of ShiftLeft(int). Because we can
save some computations, this function is a little bit faster
than the genaral version of the shiftleft operator. The shift
on only one position is a frequently operation. Thereby we have decided
to provide this version separately.
*/
bool ShiftLeft1(){
unsigned long tmp=0;
bool of = ((1uL << (numberOfBitsM1)) & value[size-1]) !=0;
for(int i=size-1; i>=0; i--){
value[i] = value[i] << 1;
if(i>0){
tmp = value[i-1];
tmp = tmp >> (numberOfBitsM1);
value[i] = value[i] | tmp;
}
}
return of;
}
/*
~ShiftLeft~
This function shifts the content of this bigint to left on pos positions.
The signum is not affected by using this function.
*/
void ShiftLeft(const unsigned int pos){
if(pos==0)
return;
int jump = pos / numberOfBits;
int shift = pos % numberOfBits;
unsigned long tmp;
for(int i=size-1;i>=0;i--){
if(i-jump<0){ // fill with zeros
value[i] = 0uL;
}else{
value[i] = value[i-jump] << shift;
if(i-jump-1<0){
tmp=0;
} else{
tmp = value[i-jump-1];
}
tmp = tmp >> (numberOfBits-shift);
value[i] = value[i] | tmp;
}
}
}
/*
~ShiftRight1~
This operator shifts the value of this bigint 1 position
to right and fills the left side with zero.
*/
void ShiftRight1(){
for(unsigned int i=0;i<size;i++){
value[i] = value[i] >> 1;
if(i<size-1){
value[i] = value[i] | (( value[i+1] & 1UL) << (numberOfBitsM1));
}
}
}
/*
~ShiftRight~
This is the general version of the shiftright operator.
*/
void ShiftRight(const int positions){
if(positions==0)
return;
int jump = positions / numberOfBits;
int shift = positions % numberOfBits;
unsigned long tmp;
for(unsigned int i=0;i<size;i++){
if( (i+jump)>=size){
value[i] = 0UL;
}else{
if(i+jump+1<=size){
tmp=0UL;
}else{
tmp = value[i+jump+1] << (numberOfBits-shift);
}
value[i] = (value[i+jump] >> shift) | tmp;
}
}
}
/*
~ReadFrom~
This function reads the value of this bigint from a long value;
*/
void ReadFrom(const long value){
unsigned long v;
if(value<0){
signum=false;
v = -value;
}else{
signum=true;
v = value;
}
for(unsigned int i=1;i<size;i++){
this->value[i]=0UL;
}
unsigned long pos=0;
this->value[0]=0;
while(v>0){
pos++;
if((v&1UL)!=0){
this->value[0] = this->value[0] | 1UL<<(pos-1);
}
v = v /2;
}
}
/*
~ReadFrom~
*/
bool ReadFrom(char* content,size_t length){
// test the first character
ReadFrom(0); // first initialization
if(length <=0)
return false;
char c;
c = content[0];
int state=0;
bool ok = true;
unsigned int pos = 0;
bool overflow;
BigInt<size> digit;
bool sig = true;
while(ok && (pos<length)){
switch(state){
case 0 : switch(c){
case '+' : state=1; break;
case '-' : state=1; sig=false; break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
ReadFrom(valueof(c));
state=2;
break;
default : ok = false;
}
break;
case 1 : switch(c){
case ' ' : state=2; break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
ReadFrom(valueof(c));
state=2; break;
default : ok = false;
}
break;
case 2 : switch(c){
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
MulInternal(TEN,overflow);
if(overflow){
ok=false;
}
digit.ReadFrom(valueof(c));
AddInternal(digit,overflow);
if(overflow){
ok = false;
}
break;
default : ok = false;
}
break;
default : assert(false); // unknown state
}
pos++;
if(pos<length)
c = content[pos];
}
signum = sig;
return ok;
}
/*
~GetMax~
Return the maximal representable value of this instantiation of this class.
*/
static BigInt<size> GetMax(){
// create a long value with 1 at each position
unsigned long pos = 1;
unsigned long v = 0;
for(int i=0;i<numberOfBits;i++){
v = v | pos;
pos = pos << 1;
}
BigInt<size> result(0);
for(unsigned int i=0;i<size;i++){
result.value[i]=v;
}
return result;
}
/*
~GetMin~
Return the mininimum representable value.
*/
static BigInt<size> GetMin(){
BigInt<size> result = GetMax();
result.signum=false;
return result;
}
/*
~WriteTo~
Writes this number binary to ~o~ without leading zeros.
*/
void WriteTo(std::ostream& o)const{
if(!signum)
o << "-";
bool write=false;
unsigned long pos;
unsigned long test;
for(int i=size-1;i>=0;i--){
for(int j=(numberOfBitsM1);j>-1;j--){
pos = 1UL << j;
test=value[i]&pos;
if(test!=0){
write=true;
o << "1";
} else{
if(write) o << "0";
}
}
}
}
/*
~WriteComplete~
Writes this number to o in binary format
with leading zeros and signum.
*/
void WriteComplete(std::ostream& o)const{
if(!signum)
o << "-";
else
o << "+";
unsigned long pos;
unsigned long test;
for(int i=size-1;i>=0;i--){
for(int j=(numberOfBitsM1);j>-1;j--){
pos = 1UL << j;
test=value[i]&pos;
if(test!=0){
o << "1";
} else{
o << "0";
}
}
}
}
/*
~WriteTo10~
This function writes the value of this bigint to o
using a base of ten.
*/
void WriteTo10(std::ostream& o)const{
unsigned int maxsize = size*10;
unsigned char work[maxsize];
for(unsigned int i=0;i<maxsize;i++){
work[i]=0;
}
unsigned long pos;
bool run = false;
bool one = false;
unsigned long v;
for(int i=(size-1);i>=0;i--){
for(int j=(numberOfBitsM1);j>-1;j--){
pos = 1UL << j;
v = value[i]&pos;
one = v!=0;
if(one){
if(!run){
run = true;
plus1(work,maxsize);
}else{
mul2(work,maxsize);
plus1(work,maxsize);
}
}else{ // zero found
if(run){
mul2(work,maxsize);
}
}
}
}
if(!signum )
o << "-";
write(o,work,maxsize);
}
/*
2.2.2 Operators
These operators can be used for making computation on
BigInt instances like on usual integer types.
*/
/*
~Arithmetik operators~
*/
BigInt<size> operator-(const BigInt<size>& i2){
bool dummy;
return Minus(i2,dummy);
}
BigInt<size> operator+(const BigInt<size>& i2){
bool dummy;
return Add(i2,dummy);
}
BigInt<size> operator*(const BigInt<size>& i2){
bool dummy;
return Mul(i2,dummy);
}
BigInt<size> operator/(const BigInt<size>& i2){
BigInt<size> dummy;
return Div(i2,dummy);
}
BigInt<size> operator%(const BigInt<size>& i2){
BigInt<size> remainder;
Div(i2,remainder);
return remainder;
}
/*
~Assignment operator~
*/
BigInt<size>& operator=(const BigInt<size>& i2){
Equalize(i2);
return *this;
}
/*
~Comparision operators~
*/
bool operator<(const BigInt<size>& i1){
return CompareTo(i1)<0;
}
bool operator>(const BigInt<size>& i1){
return CompareTo(i1)>0;
}
bool operator==(const BigInt<size>& i1){
return Equals(i1);
}
bool operator!=(const BigInt<size>& i1){
return !Equals(i1);
}
}; // end of class
/*
~Output Operator~
*/
template<unsigned int size> std::ostream&
operator<<(std::ostream &o,const BigInt<size>& i){
i.WriteTo10(o);
return o;
}
/*
Definitions of some constants. Here are frequently used constants
defined.
*/
template<unsigned int size> const BigInt<size> BigInt<size>::ONE(1);
template<unsigned int size> const BigInt<size> BigInt<size>::ZERO(0);
template<unsigned int size> const BigInt<size> BigInt<size>::TEN(10);
#endif