大整数运算的实现原理
写一个BigInt(大整数)类,其中数据成员是一个顺序表,用来保存大整数.其方法是将数的每一位数(0~9中的一个)存放在每一个节点中,高位存放在高下标,低位存放在低下标.注意:实现时下标是从1开始的.类中的运算如Add(), Sub()等全用友元函数来实现.类中还有一些辅助的函数,如push_back(), push_front()等是用BigInt的数据成员调用了顺序表中的函数.还有一些其他函数在代码中有所说明.
顺序表中提供了一些顺序表的基本操作,构造,插入,以及插入时容量不足的处理函数等.
代码
seqlist.h
#ifndef _SEQLIST_H
#define _SEQLIST_H
#include"utili.h"
template<typename Type>
class SeqList
{
public:
SeqList(size_t sz = DEFAULT_SIZE)
{
capacity = sz > DEFAULT_SIZE ? sz : DEFAULT_SIZE;
base = new Type[capacity + 1]; //空出一个0下标
memset(base, 0, sizeof(Type) * (capacity+1));
size = 0;
}
SeqList& operator=(const SeqList &sql)
{
if (this != &sql)
{
Type *new_base = new Type[sizeof(Type) * sql.Capacity()+1]; //申请新空间
memset(new_base, 0, sizeof(Type) * (sql.Capacity()+1)); //赋初始值
for (ulong i = 1; i <= sql.Size(); i++) //赋值数据
new_base[i] = sql.base[i];
delete []base; //释放旧空间
base = new_base; //指向新空间
size = sql.Size();
capacity = sql.Capacity();
}
return *this;
}
~SeqList()
{
delete []base;
base = NULL;
capacity = size = 0;
}
public:
bool isfull()const{return size >= capacity;}
bool isempty()const{return size == 0;}
public:
bool push_back(const Type &x)
{//尾部插入
if(isfull() && !Inc()) //顺序不能改变
return false;
base[++size] = x;
return true;
}
bool push_front(const Type &x)
{//头部插入
if (isfull() && !Inc())
return false;
size++;
//移动数据并插入
for (ulong i = size-1; i >= 1; i--)
base[i+1] = base[i];
base[1] = x;
return true;
}
public:
bool pop_back()
{//尾部删除
if (isempty())
return false;
base[size--] = 0;
}
bool pop_front();
void reset()
{//顺序表清空
memset(base, 0, sizeof(Type) * (capacity+1));
size = 0;
}
public:
ulong Size()
{
return size;
}
ulong Size()const
{
return size;
}
ulong Capacity()
{
return capacity;
}
ulong Capacity()const
{
return capacity;
}
public:
Type& operator[](ulong pos)
{
return base[pos];
}
Type& operator[](ulong pos)const
{
return base[pos];
}
protected:
bool Inc()
{//空间不足时处理函数
Type *new_base = new Type[capacity + INC_SIZE + 1]; //申请新空间
if (new_base == NULL)
return false;
memset(new_base, 0, sizeof(Type)*(capacity+INC_SIZE+1)); //赋值0
memcpy(new_base, base, sizeof(Type)*(capacity+1)); //数据移动复制
capacity += INC_SIZE; //容量增加INC_SIZE
delete []base; //释放旧空间
base = new_base; //base指向新的空间
return true;
}
private:
enum{DEFAULT_SIZE=20, INC_SIZE=10}; //默认大小,增长长度
Type *base; //指向数组空间的指针
ulong capacity; //容量
ulong size; //顺序表大小
};
#endif
bigint.h
#include "seqlist.h"
class BigInt
{
public:
BigInt();
BigInt(int x);
BigInt& operator=(const BigInt &bt);
public:
void LoadData(int sz); //随机加载一个长度sz的整数
void PrintData()const; //输出整数
ulong size()const; //返回整数的位数
void reset(); //将整数置为空
public:
bool push_back(uchar x); //从后面插入一位数
bool push_front(uchar x); //从前面插入一位数
bool pop_back(); //从后面删除一位数
public:
uchar& operator[](ulong pos); //取出pos下标的数字
uchar& operator[](ulong pos)const;
public:
bool operator>=(const BigInt &bt)const;
bool operator<(const BigInt &bt)const;
bool operator<=(const BigInt &bt)const;
bool operator>(const BigInt &bt)const;
bool operator==(const BigInt &bt)const;
bool operator!=(const BigInt &bt)const;
public:
BigInt& operator++();
BigInt operator++(int);
public:
BigInt operator-(const BigInt &bt);
BigInt& operator+=(const BigInt &bt);
BigInt& operator*=(const BigInt &bt);
public:
//大整数bt1运算bt2,结果保存在bt中
friend void Add(BigInt &bt, const BigInt &bt1, const BigInt &bt2);
friend void Sub(BigInt &bt, const BigInt &bt1, const BigInt &bt2);
friend void Mul(BigInt &bt, const BigInt &bt1, const BigInt &bt2);
friend void Div(BigInt &bt, const BigInt &bt1, const BigInt &bt2);
friend void Mod(BigInt &bt, const BigInt &bt1, const BigInt &bt2);
friend void Square(BigInt &bt, const BigInt &bt1);
friend void Power(BigInt &bt, const BigInt &bt1, long n);
friend void Power(BigInt &bt, const BigInt &bt1, const BigInt &bt2);
private:
SeqList<uchar> big; //用顺序表存放大数
};
bigint.cpp
#include "bigint.h"
#include <cmath>
//Add(),Sub(),Mul()调用的函数,用来计算数的一位的结果
uchar AddItem(uchar a, uchar b, uchar &sign);
uchar SubItem(uchar a, uchar b, uchar &sign);
uchar MulItem(uchar a, uchar b, uchar &sign);
BigInt::BigInt()
{}
BigInt::BigInt(int x)
{
if (x == 0)
{
push_back(0);
return;
}
while (x > 0)
{
push_back(x % 10);
x /= 10;
}
}
BigInt& BigInt::operator=(const BigInt &bt)
{
if (this != &bt)
{
(*this).big = bt.big;
}
return *this;
}
///////////////////////////////////////////////////////////////
void BigInt::LoadData(int sz)
{//按位数置一个随机数
srand(time(NULL));
for (ulong i = 0; i < sz; i++)
{
push_back(rand() % 10);
}
}
void BigInt::PrintData()const
{//输出数
for (ulong i = size(); i >= 1; i--)
{
cout << (int)big[i];
}
cout << endl;
}
////////////////////////////////////////////////////////
//调用了seqlist的成员函数
bool BigInt::push_back(uchar x)
{
return big.push_back(x);
}
bool BigInt::push_front(uchar x)
{
return big.push_front(x);
}
bool BigInt::pop_back()
{
big.pop_back();
}
void BigInt::reset()
{
big.reset();
}
ulong BigInt::size()const
{
return big.Size();
}
////////////////////////////////////////////////////////
uchar& BigInt::operator[](ulong pos)
{
return big[pos];
}
uchar& BigInt::operator[](ulong pos)const
{
return big[pos];
}
///////////////////////////////////////////////////////////
bool BigInt::operator>=(const BigInt &bt)const
{
if (size() > bt.size())
return true;
else if (size() < bt.size())
return false;
ulong i;
i = size();
while (i >= 1)
{
if ((*this)[i] > bt[i])
return true;
else if((*this)[i] < bt[i])
return false;
i--;
}
return true;
}
bool BigInt::operator<(const BigInt &bt)const
{
return !((*this) >= bt);
}
bool BigInt::operator==(const BigInt &bt)const
{
if (size() != bt.size())
return false;
ulong i = size();
while (i >= 1)
{
if ((*this)[i] != bt[i])
return false;
--i;
}
return true;
}
bool BigInt::operator!=(const BigInt &bt)const
{
return !((*this)==bt);
}
bool BigInt::operator<=(const BigInt &bt)const
{
return ((*this)<bt || (*this)==bt);
}
//////////////////////////////////////////////////////
BigInt& BigInt::operator++()
{
ulong i = 1;
uchar sign = 1;
while (sign == 1 && i <= size())
{
(*this)[i] = AddItem((*this)[i], 0, sign);
++i;
}
if (sign == 1)
push_back(sign);
return *this;
}
BigInt BigInt::operator++(int)
{
BigInt tmp = *this;
++*this;
return tmp;
}
BigInt& BigInt::operator+=(const BigInt &bt)
{
ulong i = 1;
ulong j = 1;
uchar sign = 0;
while(i<=size() && j<=bt.size())
{
(*this)[i] = AddItem((*this)[i], bt[j], sign);
++i;
++j;
}
while(sign>0 && i<=size())
{//*this没有加完
(*this)[i] = AddItem((*this)[i], 0, sign);
++i;
}
while(j <= bt.size())
{//bt没有加完的情况,之所以和上一个while循环内部有所不同,
//是为了保证*this的size的正确性
uchar sum = AddItem(0, bt[j], sign);
push_back(sum);
++j;
}
if(sign > 0)
push_back(sign);
return *this;
}
BigInt& BigInt::operator*=(const BigInt &bt)
{
BigInt tmp;
Mul(tmp, (*this), bt);
(*this) = tmp;
return *this;
}
BigInt BigInt::operator-(const BigInt &bt)
{
assert(*this >= bt);
BigInt tmp;
Sub(tmp, *this, bt);
return tmp;
}
///////////////////////////////////////////////////////////
void Add(BigInt &bt, const BigInt &bt1, const BigInt &bt2)
{
bt.reset();
ulong i = 1;
ulong j = 1;
uchar sign = 0;
uchar sum;
while(i<=bt1.size() && j<=bt2.size())
{
sum = AddItem(bt1[i++], bt2[j++], sign);
bt.push_back(sum);
}
while(i <= bt1.size())
{//bt1位数 > bt2位数
sum = AddItem(bt1[i++], 0, sign);
bt.push_back(sum);
}
while(j <= bt2.size())
{//bt2位数 > bt1位数
sum = AddItem(0, bt2[j++], sign);
bt.push_back(sum);
}
if(sign > 0) //最高位的进位
bt.push_back(sign);
}
void Sub(BigInt &bt, const BigInt &bt1, const BigInt &bt2)
{
assert(bt1 >= bt2);
bt.reset();
if(bt1 == bt2)
{
bt.push_back(0);
return;
}
ulong i = 1;
ulong j = 1;
uchar sign = 0;
uchar sub;
while(i<=bt1.size() && j<=bt2.size())
{
sub = SubItem(bt1[i++], bt2[j++], sign);
bt.push_back(sub);
}
while(i<=bt1.size())
{
sub = SubItem(bt1[i++], 0, sign);
bt.push_back(sub);
}
for (ulong k = bt.size(); k >= 1; k--)
{//除去前置的0
if (bt[k] == 0)
bt.pop_back();
else
break;
}
}
#if 0
void Mul(BigInt &bt, const BigInt &bt1, const BigInt &bt2)
{//效率低的版本
for (BigInt i = 0; i < bt2; ++i)
{//bt2个bt1加到bt上
bt += bt1;
}
}
#endif
void Mul(BigInt &bt, const BigInt &bt1, const BigInt &bt2)
{
bt.reset();
if (bt1 == 0 || bt2 == 0)
{//有一个数为0,直接返回0
bt.push_back(0);
return;
}
uchar sign = 0;
for (ulong i = 1; i <= bt2.size(); i++)
{
BigInt mul; //保存bt1和bt2每一位的乘积
for (ulong j = 1; j <= bt1.size(); j++)
{
uchar x = MulItem(bt2[i], bt1[j], sign);
mul.push_back(x);
}
if (sign > 0)
{
mul.push_back(sign);
sign = 0;
}
//bt += mul * pow(10, i-1);
for (ulong k = 1; k < i; k++)
mul.push_front(0); //提升mul
bt += mul;
}
}
void Div(BigInt &bt, const BigInt &bt1, const BigInt &bt2)
{
assert(bt2 != 0); //除数不能为0
bt.reset();
if (bt1 < bt2) //若bt1 < bt2, 则返回0
{
bt.push_back(0);
return;
}
BigInt tmp; //被除数
bool on_off = false; //定义一个开关,用于排除前置的0值
for (ulong i = bt1.size(); i >= 1; i--) //从最高位开始
{
tmp.push_front(bt1[i]);
uchar shang = 0; //保存商值
while (tmp >= bt2 && tmp - bt2 >= 0) //1
{
shang++;
//tmp -= bt2;
tmp = tmp - bt2;
}
if (tmp == 0)
tmp.reset();
if (shang != 0)
{
bt.push_front(shang);
on_off = true;
}
else if (shang == 0 && on_off)
bt.push_front(shang);
}
}
///////////////////////////////////////////////////////////////
void Square(BigInt &bt, const BigInt &bt1)
{//bt ^ 2
Mul(bt, bt1, bt1);
}
void Power(BigInt &bt, const BigInt &bt1, long n)
{//bt1 ^ n
if (bt1 == 0)
{
bt = 0;
return;
}
if (n == 0)
{
bt = 1;
return;
}
bt = 1;
for (long i = 0; i < n; i++)
{//n个bt1相乘
bt *= bt1;
}
}
void Power(BigInt &bt, const BigInt &bt1, const BigInt &bt2)
{//bt1 ^ bt2
if (bt1 == 0)
{
bt = 0;
return;
}
if (bt2 == 0)
{
bt = 1;
return;
}
bt = 1;
for (BigInt i = 0; i < bt2; ++i)
{//bt2个bt1相乘
bt *= bt1;
}
}
void Mod(BigInt &bt, const BigInt &bt1, const BigInt &bt2)
{//bt1 % bt2
if (bt1 <= bt2)
{
bt = 0;
return;
}
BigInt cnt; //bt1中有cnt个bt2
BigInt tmp;
Div(cnt, bt1, bt2);
//bt1减去cnt个bt2, 结果即为余数
Mul(tmp, bt2, cnt);
Sub(bt, bt1, tmp);
}
///////////////////////////////////////////////////////////////
uchar AddItem(uchar a, uchar b, uchar &sign)
{//计算一位数加法
uchar sum = a + b + sign;
#if 0
if (sum >= 10)
{
sum -= 10;
sign = 1;
}
else
sign = 0;
#endif
sign = sum / 10;
sum %= 10;
return sum;
}
uchar SubItem(uchar a, uchar b, uchar &sign)
{//一位数相减
uchar sub;
if (a - sign >= b)
{//足够减
sub = a - b - sign;
sign = 0;
}
else
{//借位相减
sub = a + 10 - b - sign;
sign = 1;
}
return sub;
}
uchar MulItem(uchar a, uchar b, uchar &sign)
{//一位数相乘
uchar mul = a * b + sign;
sign = mul / 10;
mul %= 10;
return mul;
}
utili.h
#ifndef __UTILI_H
#define __UTILI_H
#include <iostream>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
using namespace std;
typedef unsigned long ulong;
typedef unsigned char uchar;
#endif
Makefile
bigmain : bigmain.o bigint.o
g++ -o bigmain bigmain.o bigint.o
bigmain.o : bigmain.cpp
g++ -o bigmain.o -c bigmain.cpp -g
bigint.o : bigint.cpp
g++ -o bigint.o -c bigint.cpp -g
.PHONY:clean
clean:
rm *.o bigmain
测试
测试很简单,只要定义BigInt对象,并调用友元函数即可.
#include "unistd.h"
#include "bigint.h"
int main()
{
BigInt bt;
BigInt bt1, bt2;
bt1.LoadData(10);
bt1.PrintData();
sleep(1);
bt2.LoadData(10);
bt2.PrintData();
//Add(bt, bt1, bt2);
//Sub(bt, bt1, bt2);
//Mul(bt, bt1, bt2);
//Div(bt, bt1, bt2);
//Square(bt, bt1);
//Power(bt, bt1, 100);
//Power(bt, bt1, bt2);
Mod(bt, bt1, bt2);
bt.PrintData();
return 0;
}