10進制大數算法,支持+、-、*、/、%以及一般的比較運算符,支持字符串方式讀入以及輸出大數
#pragma once
#include <iostream>
#include <string>
using namespace std;
#define SWAP(x,y,t) ((t)=(x),(x)=(y),(y)=(x))
#define MIN(x,y) (x)>(y)?(y):(x)
#define MAX(x,y) (x)>(y)?(x):(y)
#define BASE 10000 //大數以每位十進制數的方式存儲
//乘法實現,計算A*B,結果返回到 C,函數結果爲乘法結果的長度
#define MAX_SIZE 128
//一般將算術和關係操作符定義非成員函數,而將賦值操作符定義爲成員:
//大數以小端格式存儲
struct BigNum
{
int len;
int v[MAX_SIZE];
BigNum()
{
len=0;memset(v,0, sizeof(v));
}
BigNum(const char* num)
{
*this=num;
}
BigNum(int num)
{
len=0;
for(; num>0; num/=BASE)
v[len++] = num%BASE;
}
BigNum& operator=(const char* num)
{
int l=strlen(num);
int n=(l%4)?(l%4):4;
len=0;
char x[5]={0};
memcpy(x,num, n );
v[(l+4-1)/4-1] = atoi(x);
len++;
for(int i=(l+4-1)/4-2,j=n; i>=0; i--,j+=4)
{
memcpy(x, num+j, 4);
v[i] = atoi(x);
len++;
}
return *this;
}
};
bool operator<(const BigNum& left,const BigNum& right)
{
int i;
if(left.len!=right.len) return left.len<right.len;
for(i=left.len-1; i>=0 && left.v[i]==right.v[i]; i--)
;
return i>0? left.v[i]<right.v[i]: 0;
}
bool operator>(const BigNum& left,const BigNum& right)
{
return right<left;
}
bool operator==(const BigNum& left,const BigNum& right)
{
return (!(left<right)) && (!(right<left));
}
bool operator<=(const BigNum& left,const BigNum& right)
{
return (left<right) || (left==right);
}
bool operator>=(const BigNum& left,const BigNum& right)
{
return right<=left;
}
BigNum operator+(const BigNum& left,const BigNum& right)
{
int n = MAX(left.len,right.len);
int x=0,i;
BigNum result;
for(i=0; i<n; i++)
{
if(i<left.len) x+=left.v[i];
if(i<right.len) x+=right.v[i];
result.v[i] = x%BASE;
x/=BASE;
}
if(x!=0) result.v[i++] = x;
result.len = i;
return result;
}
BigNum operator-(const BigNum& left,const BigNum& right)
{
BigNum result;
int i,x=0;
for(i=0; i<left.len; i++)
{
result.v[i] = left.v[i] - x;
if(i<right.len) result.v[i] -= right.v[i];
if(result.v[i]<0) result.v[i] += BASE, x = 1;
else x=0;
}
result.len = i;
while(result.len>0&&result.v[result.len-1]==0) result.len--;
return result;
}
BigNum operator*(const BigNum& left,const BigNum& right)
{
BigNum result;
int c0,c1,c2;//存數臨時結果
int tx,ty;
int len=left.len+right.len;
int *templ,*tempr;
c0 = c1 = c2 = 0;
for(int i=0; i<len; i++)//i爲本次計算在結果中所處的級別,這裏一個整形爲一個級別
{
ty = MIN(i, right.len-1);
tx = i-ty;
templ = (int*)(left.v + tx);
tempr = (int*)(right.v+ ty);
int n = MIN( left.len-tx, ty+1);//本級別可計算的次數
c0 = c1; c1 = c2; c2 = 0; //上次計算結果向下移一個級別,進入本次計算
for(int j=0; j<n; j++)
{
int x=*templ++, y=*tempr--;
c0 += x*y;
/*_asm //mul operation
{
pushad
mov eax,x
mov ebx,y
mul ebx //無符號乘法指令
add c0,eax
//adc c1,edx
//adc c2,0
popad
}*/
}
result.v[i]=c0%BASE;
c1+=c0/BASE;
c2+=c1/BASE;
}
//計算長度
for(int i=len-1; i >= 0; i--)
if (result.v[i]==0)
len--;
else
break;
result.len = len;
return result;
}
BigNum operator/(const BigNum& a,const BigNum& b)
{
BigNum tmp, mod, res;
int i, lf, rg, mid,base=BASE;
mod.v[0] = mod.len = 0;
for (i = a.len - 1; i >= 0; i--)
{
//從最高4位開始,每次增加一個4位試商
mod = mod * base + a.v[i];
//二分法尋找mod/b的商
for (lf = 0, rg = base -1; lf < rg; )
{
mid = (lf + rg + 1) / 2;
if (b * mid <= mod)
lf = mid;
else
rg = mid - 1;
}
//存儲結果並將剩餘的數繼續試商
res.v[i] = lf;
mod = mod - b * lf;
}
res.len = a.len;
while (res.len > 0 && res.v[res.len - 1] == 0) res.len--;
return res; // return mod 就是%運算
}
BigNum operator%(const BigNum& a,const BigNum& b)
{
BigNum tmp, mod, res;
int i, lf, rg, mid,base=BASE;
mod.v[0] = mod.len = 0;
for (i = a.len - 1; i >= 0; i--)
{
//從最高4位開始,每次增加一個4位試商
mod = mod * base + a.v[i];
//二分法尋找mod/b的商
for (lf = 0, rg = base -1; lf < rg; )
{
mid = (lf + rg + 1) / 2;
if (b * mid <= mod)
lf = mid;
else
rg = mid - 1;
}
//存儲結果並將剩餘的數繼續試商
res.v[i] = lf;
mod = mod - b * lf;
}
res.len = a.len;
while (res.len > 0 && res.v[res.len - 1] == 0) res.len--;
return mod;// %運算
}
ostream& operator<<(ostream& os,const BigNum& num)
{
printf( "%d",num.v[num.len-1]);
for(int i=num.len-2; i>=0; i--)
printf( "%04d",num.v[i]);
return os;
}
istream& operator>>(istream& in,BigNum& num)
{
string str;
in>>str;
num=str.c_str();
return in;
}
X86版本的大數乘法簡陋實現,沒有書上的可移植性,結果以16進制存儲
只是爲了試試效果~
#include <stdio.h>
#define MIN(x,y) (x)>(y)?(y):(x)
/*#define MUL(x,y) _asm {\
"pushad\r\n"\
"mov eax,x\r\n" \
"mov ebx,y\r\n" \
"mul ebx\r\n"\
"add c0,eax\r\n" \
"adc c1,edx\r\n" \
"adc c2,0\r\n"\
"popad\r\n"\
}
*/
//乘法實現,計算A*B,結果返回到C,函數結果爲乘法結果的長度,大數整體採用小端模式存儲
int mul(int *A,int lena, int *B,int lenb, int *C)
{
int ix, iy, iz, tx, ty, pa;
int c0, c1, c2, *tmpx, *tmpy;
c0=c1=c2=0;
/* get size of output and trim */
pa = lena+lenb;
for (ix = 0; ix < pa; ix++) {
/* get offsets into the two bignums */
ty = MIN(ix, lenb-1);
tx = ix - ty;
/* setup temp aliases */
tmpx = A + tx;
tmpy = B + ty;
/* this is the number of times the loop will iterrate, essentially its
while (tx++ < a->used && ty-- >= 0) { ... }
*/
iy = MIN(lena-tx, ty+1);
/* execute loop */
c0=c1;c1=c2;c2=0;
for (iz = 0; iz < iy; ++iz) {
int i=*tmpx++,j= *tmpy--;
_asm //mul operation
{
pushad
mov eax,i
mov ebx,j
mul ebx
add c0,eax
adc c1,edx
adc c2,0
popad
}
}
/* store term */
C[ix]=c0;
}
return pa;
}
//平方計算,函數結果爲乘法結果的長度
int square(int *A,int lena, int *C)
{
int ix, iy, iz, tx, ty, pa;
int c0, c1, c2, *tmpx, *tmpy;
c0=c1=c2=0;
/* get size of output and trim */
pa = lena*2;
for (ix = 0; ix < pa; ix++) {
/* get offsets into the two bignums */
ty = MIN(ix, lena-1);
tx = ix - ty;
/* setup temp aliases */
tmpx = A + tx;
tmpy = A + ty;
/* this is the number of times the loop will iterrate, essentially its
while (tx++ < a->used && ty-- >= 0) { ... }
*/
iy = MIN(lena-tx, ty+1);
iy = MIN(iy, (ty-tx+1)>>1);
/* execute loop */
c0=c1;c1=c2;c2=0;
for (iz = 0; iz < iy; ++iz) {
int i=*tmpx++,j= *tmpy--;
_asm // 由於是平方,加兩次,省去一半的乘法指令
{
pushad
mov eax,i
mov ebx,j
mul ebx
add c0,eax
adc c1,edx
adc c2,0
add c0,eax
adc c1,edx
adc c2,0
popad
}
}
if ((ix&1)==0) // 偶數位的話需要加上中間未重複的結果
{
int i=A[ix>>1],j= A[ix>>1];
_asm //mul operation
{
pushad
mov eax,i
mov ebx,j
mul ebx
add c0,eax
adc c1,edx
adc c2,0
popad
}
}
/* store term */
C[ix]=c0;
}
return pa;
}
//求冪,lena:A的長度(4字節爲單位),exponent:指數,C:存儲結果
//這個版本的求冪只能求2^n形式的冪
int power(int *A,int lena, int exponent, int *C)
{
int len=lena,*temp,*dst=C;
int squ=0;// 可直接平方的次數
for(int t=exponent; t!=1; t>>=1)
squ++;
for(int i=0; i < squ; i++)
{
memset(C, 0 , 1024);
len = square(A,len, C);
SWAP(A,C,temp);
}
if (dst!=A) memcpy(dst,A,len);
return len;
}
void print_bignum(int *bignum,int u)
{
int first=1;
printf( "0x");
for(int i=u-1; i >= 0; i--)
if ((bignum[i]==0)&&first)
continue;
else
{
first = 0;
printf( "%08X",bignum[i]);
}
}
int main()
{
int a[] = {0x87654321,0x12345678,0x12345678,0x12345678,0x12345678,0x12345678,0x12345678,\
0x87654321,0x12345678,0x12345678,0x12345678,0x12345678,0x12345678,0x12345678,\
0x12345678,0x12345678,0x12345678,0x12345678,0x12345678,0x12345678,0x12345678,0x12345678,0x12345678,0x12345678,0x12345678};
int b[] = {0x87654321,0x12345678,0x12345678,0x12345678,0x12345678,0x12345678,\
0x87654321,0x12345678,0x12345678,0x12345678,0x12345678,0x12345678,0x12345678,\
0x12345678,0x12345678,0x12345678,0x12345678,0x12345678,0x12345678,0x12345678,0x12345678,0x12345678,0x12345678,0x12345678,0x12345678};
int c[256]={0};
int len=mul(a,sizeof (a)/sizeof( int),b,sizeof (b)/sizeof( int), c);
print_bignum(c,len);
getchar();
return 0;
}
#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
//查找指定範圍內的所有素數
//100以內的所有素數
unsigned int prime_tab[] = {
2, 3, 5, 7, 11, 13, 17,
19, 23, 29, 31, 37, 41, 43,
47, 53, 59, 61, 67, 71, 73,
79, 83, 89, 97
};
//Eratosthenes 素數篩選,取得0-num內所有的素數,c++容器版
int Eratosthenes(vector<int >& tab, unsigned int num)
{
#define TEST(p,x) (((p)%(x))!=0) //是否滿足素數條件
if(num <= 100)
{
for(int i=0; i < sizeof(prime_tab)/ sizeof(int ); i++)
{
if(prime_tab[i]<num)
tab.push_back(prime_tab[i]);
else
break;
}
return tab.size();
}
unsigned int i=(int)sqrt(( double)num);
Eratosthenes(tab, i); /*遞歸初始化i以內的素數表 */
for(; i < num; i++)// 篩選
{
bool flag=false ;
int n=tab.size();
for(vector<int >::iterator iter=tab.begin(),end=iter+n; iter != end ; iter++)
{
if( !TEST(i,*iter) )
break;
if( (iter+1)==end )
flag= true;
}
if(flag) tab.push_back(i);
}
#undef TEST(p,x)
return tab.size();
}
//Eratosthenes 素數篩選,取得 num內所有的素數
int Eratosthenes2(unsigned int num)
{
unsigned int count=0;
char *tab = new char[num+1];
memset(tab+2,1, num-2);
for(unsigned int i=2; i <= ( unsigned int )sqrt((double)num); i++)
if(tab[i]==1)
for(unsigned int j=i; j*i <= num; j++)
tab[i*j] = 0;
for(unsigned int i=2; i <= num ; i++)
if(tab[i]==1)
{
printf( "%d\t",i);
count++;
}
printf( "\n%d ",count);
delete [] tab;
return count;
}
int main()
{
vector< int> tab; //素數表容器
tab.reserve(2000); //預留空間
cout<<Eratosthenes(tab,150000); //函數返回統計個數
for(int i=0; i < tab.size(); i++) //輸出素數
printf( "%d\t", tab[i]);
getchar();
return 0;
}