大数运算(能开方、求幂、排列组合、取对数、求三角值)

趁着寒假想用C写一个模拟星体运动的程序,发现星体的数据过于庞大,于是便开始写大数运算的程序。

目前大一,难免有些错误,还请各位猿友能指出。

#include<math.h>
#include<string>
#include<iostream>


#define pi asin(1)*2
#define lon 21//数据精度
#define d 1000//数据长度
/*大数表示演示:
* 12 345 678.123 456 7->long a[lon]={2,12,345,678,123,456,700}
* 负数的转换不同,如-123 456->{1,-124,544}即-124000+544=123456
* 我们把数组a里的一个数字成为一个节,如:第0节->2,第1节->12
* 数组a表示的数A可以这样来表示:
*{
* int A=0,i=0;
* for(i=0;i<lon;i++)A+=a[i+1]*pow(d,*a-i);
* }
* 定义函数时用b和n来表示大数(big num)和普通的数(num)
* 定义函数参数时用n和num表示大数和普通数
*/
long bn0[lon] = { 0 };//0大数
long bn1[lon] = { 1,11,110 };
long bn2[lon] = { 2 ,-1,-2,-3,-4 };
long bpi[lon] = { 0,3,141,592,653,589,793,115,997,963,468,544,185,161,590,576,171,875 };
long be[lon] = { 0,02,718,281,828,459,45,073,32,29,904,425,144,195,556,640,625 };
// 4,5,965000
//一段表示3位数

//复制大数,X用于储存返回值
void copyb(long* n, long X[]) {
    int i ;
    for (i=0;i<lon;X[i]=n[i++]);
}

//复制大数的某一段,st->start,fi->finish
void copybb(long* n, long X[],int st=1,int fi=lon) {
    st = st <= 0 ? 1 : st;
    st = st > lon ? lon - 1 : st;
    long n2[lon] = { 0 };int i, j;
    for (i = st;i < fi;i++)n2[i - st + 1] = n[i];
    *n2 = *n - st + 1;
    copyb(n2, X);
}
//大数归零
void zerob(long* n) {
    copyb(bn0, n);
}

//平的读音,整理大数使大数符合格式,还有复制大数的功能
void ping(long* n,long X[]=0) {
    int k, i, f, num = n[1];
    if (X == 0)X = n;
    for (k = 1;k < lon && !n[k];k++);k--;//查询头0在何处
    if (k == lon - 1) { copyb(n,X);return; };//如果头0在lon-1则是〇大数
    for (i = 1;i < lon - k;i++)n[i] = n[i + k];//除去头0
    *n = *n - k;
    num = n[1];
    for (f = 0;num /= d;f++);f;num = n[1];//检查头是否超出d
    for (i = lon - 1;i > f;i--)n[i] = n[i - f];*n = *n + f;
    for (i = f + 1;i >= 1;i--) { n[i] = num % d; num /= d; }

    for (i = lon - 1;i >= 2;i--) {
        if (n[i] >= d)
        {
            n[i - 1]++; n[i] -= d;
        }
        if (n[i] < 0) { n[i - 1]--; n[i] += d; }
    }
    if (!n[1] || abs(n[1]) >= d) ping(n,X);
    for (i = 2;i < lon;i++)
        if (abs(n[i]) >= d || n[i] < 0)ping(n, n); 
    {copyb(n, X);return;}
}

//与下面的prnum(print num)配套,补〇
void seentzer(long n) {
    int i = 2;
    (n /= 10) ? i-- : 0;(n /= 10) ? i-- : 0;
    (n /= 10) ? i-- : 0;
    for (;i>0;i--)printf("0");
}
//打印大数
void prnum(long* n,std::string str1="\n", std::string str2 = "\n") {
    std::cout << str1;
    int i = n[0];
    printf("[%d]", n[0]);
    if (-1 == *n)printf("0.");
    for (i = 0;i < lon-1;i++) {
        seentzer(n[i+1]);
        printf("%d,", n[i+1]);
        if (i == *n)printf(".");
    }
    std::cout << str2;
}
//大数相加
   void addbb(long* n1, long* n2,long X[]=0) {//1
    ping(n1,n1);ping(n2,n2);
    if (X == 0)X = n2;
    long in[lon * 2] = { 0 }, * a;
    int i, j;
    if (*n1 < *n2) { a = n1;n1 = n2;n2 = a; }
    *in = *n1;
    for (i = 1;i < lon ;i++) {//2
        if (i >*n1 - *n2 && i < lon) { in[i] = n1[i] + n2[i - *n1 + *n2]; }
        if (i <= *n1 - *n2)in[i] = n1[i];
        if (i >= lon)
            in[i] = n2[i + *n2 - *n1];
    }//2
    ping(in, X);
}//1

   
   //大数加普通数
   void addnb(long* n1, long double num,long X[]=0) {
       if (X == 0)X = n1;
       long a[lon] = { 0 }, * n2;
       int in, i, f = 1;long double fl;
       in = (int)num;
       fl = num;
       a[0] = 0;
       a[1] = in;
       //0.123,456,789,1
       for(i=2;i<lon;i++){fl = (fl-a[i-1])*d;a[i] = (int)fl; }
       ping(n1,n1);ping(a,a);
       addbb(n1, a, X);
   }

   //普通数加普通数
   void addnn(long double num1, long double num2, long X[]) {
       long n[lon] = { 0 };
       addnb(bn0, num1, n);
       addnb(n, num2, X);
   }
   //大数取负(minus sign)
   void musgb(long* n,long X[]=0) {
       if (X == 0)X = n;
       int i = 1;long* n1 = n;
       X[0] = n[0];
       for (i = 1;i < lon;i++) {
           X[i] = -n[i]; 
       }
   }


   //相减(minus),n=1表示n1-n2,n=0表示n2-n1
   void mnsbb(long* n1, long* n2,long X[]=0,int n=1) {
       if (X == 0)X = n2;
       long n3[lon * 2] = { 0 },*a;
       if (n) { musgb(n2, n3), a = n1; }
       else { musgb(n1, n3);a = n2; }
       ping(a,a);ping(n3,n3);
       addbb(a, n3, n3);ping(n3, X);
   }
   //相减,n=1表示n1-num;n=0表示num-n1
   void mnsnb(long* n1, long double num, long X[]=0, int n = 1) {
       if (X == 0)X = n1;
       ping(n1, n1);
       if (n) { addnb(n1, -num, X);return; }
       else { long n3[lon * 2] = { 0 };musgb(n1, n3);
           addnb(n3, num, X);
       }
   }

   //相乘(multiply)head表示d的head次幂
   void mtpnb(long* n1,long double num,long X[]=0,int head=0) {
       if (X == 0)X = n1;
       int in=(int)num;long double fl = num - in;
       int i,j;
       long sum[lon*2] = { 0 };
       
           long n2[lon] = { 0 };
           ping(n1, n2);
           *n2 += head;
           *sum = *n2;
           for (i = 1;i < lon;i++)sum[i] =n2[i]*in;
           ping(sum, sum);
           //addbb(sum, n2, sum);
       
       for (j = 1;j<lon;j++) {
           copyb(n1, n2);n2[0] = *n2-j+head;
           fl *= d;
           for (i = 1;i < lon;i++) { n2[i] *=(int)fl; }
           
           addbb(sum, n2, sum);
           fl = (fl-(int)fl) ;
           
       }
       ping(sum, X);
   }

   void mtpbb(long* n1, long* n2, long X[]=0) {
       float cmpnb(long* n1, long double num);
       if (X == 0)X = n2;
       long n3[lon]={0},sum[lon]={0};
       long n4[lon] = { 0 };
       int i, j;ping(n1, n4);
       for (i = 1;i < lon;i++) {
           ;n4[0] =*n1+ 1-i;
           mtpnb(n4, n2[i], n3);
           addbb(n3, sum, sum);
       }
       ping(sum, X);
   }
   void mtpnn(long double num1, long double num2, long X[]) {
       long n[lon] = { 0,1 };
       mtpnb(n, num1, n);
       mtpnb(n, num2, X);
   
   }
   //相除(divide)
   void dvdbb(long* n1, long* n2, long x[]=0, int n = 1) {
       float cmpnb(long* n1, long double num);
       long X[lon] = {0};
       
       long sum[lon] = { 0 }, n3[lon] = { 0 }, n4[lon] = { 0 };
       int i,j;ping(n1, n4);ping(n2, n3);
       int f=1;
       if (cmpnb(n3, 0) < 0) { musgb(n3, n3); f *= -1; }
       if (cmpnb(n4, 0) < 0) { musgb(n4, n4); f *= -1; }
       X[0] = *n1 - *n2;
       *n4 = 0;*n3 = 0;
       for (j = 1;j < lon;j++) {
           for (i = 1;i < d;i++) {
               mnsbb(n4, n3, n4);
               ping(n4, n4);
               if (n4[1] < 0||i>=d) { i-=1;break; }}
           addbb(n4, n3, n4);
           n3[0] -= 1;
           X[j] = i; }
       if(x)mtpnb(X,f,x);
       else mtpnb(X, f, n2);
       }
   
   void dvdnn(long double num1, long double num, long X[], int n = 1) {

       long sto;int i,j,k;
       long n1[lon] = { 0 }, n2[lon] = { 0 };
       if (!n) { num1 += num;num = num1 - num;num1 -=  num; } 
       addnb(bn0, num1,n1);addnb(bn0, num, n2);
       dvdbb(n1, n2, X);

   }

   void dvdnb(long *n1,long double num,long X[]=0,int n=1) {
       if (X == 0)X = n1;

       int i;long sum[lon] = { 0 },n2[lon]={0},n3[lon]={0};
        addnb(bn0, num, n2);
       if (n) { dvdbb(n1, n2, X); }
       else { dvdbb(n2, n1, X); }
   }

  
   long double mysqr(long double a, int m) {
       long double x = 1;int i,j = 300;

       for (;j--;printf("\n迭代%d次->%.36f\n", j, x))
           for (i = j, x = 1;i--;)
           //    x = (a * (m - 1) / x + pow(x, m -1)) / m;
            x = (  a *pow(x, 1 - m) +(m - 1) * x) / m;
       return x;
   }
  

   //整数型次幂(即num为int型)平方,n等于0的那一功能还没设计好
   void powin(long* n1, int num, long X[] = 0, int n = 1) {
       if (X == 0)X = n1;long n2[lon] = { 0 }, x[lon] = { 0 };
       if (num < 0) { num *= -1;dvdnb(n1, 1, n2, 0); }
       else ping(n1, n2);

       if (n) {
           if (num == 0) { zerob(X);addnb(X, 1, X);return; }
           for (ping(n2, x);--num;)mtpbb(n2, x, x);
       }
       else {
           long n2[lon] = { 0 };ping(n1, n2);
           for (;;)mtpnb(X, num, X);
       }ping(x, X);
   }
 
   //整数型次方(即num为int型)平方
 void sqrin(long* n1, int num, long X[] = 0) {
       int i, j = 100;long x[lon] = {0,1}, re[4][lon] = {0};
       if (X == 0)X = n1;
       for (;j--;)
       {// x = (  a *pow(x, 1 - m) +(m - 1) * x) / m;
           powin(x, 1 - num, re[1]);//2
           mtpbb(re[1], n1, re[1]);//3
           mtpnb(x, num - 1, re[2]);//4
           addbb(re[1], re[2], re[3]);//5
           dvdnb(re[3], num, x);//6
       }
       ping(x, X);
   }
 //考录到幂很容易把大数弄炸导致精度不高,而且也不怎么常用,故未写小数型幂和开方

 //取余数(remainder)
       void rmdbb(long* n1, long *n2, long X[] = 0,int n=1) {
            long *n3,*n4,re[lon]={0};
            if (n) { n3 = n1;n4 = n2; }
            else { n3 = n2;n4 = n1; }
            ping(n3, n3);ping(n4, n4);
            dvdbb(n3, n4, re);
            copybb(re,re,re[0]+2);
            mtpbb(re, n4, re);
           // mnsbb(n3, re, re);
            ping(re, X); 
   }
       void rmdnb(long* n1, long double num, long X[] = 0, int n = 1) {
           long n2[lon] = { 0 };
           addnb(bn0, num, n2);
           rmdbb(n1, n2, X, n);
       }
       //比较大小
       float cmpbb(long* n1, long* n2) {
           ping(n1, n1);ping(n2, n2);
           int f, i;
           for (i = 0;i < lon;i++)  if (n1[i] != n2[i]) {
               if (n1[i] > n2[i])return i + 0.1;
               else return -i - 0.1;
           }
           return 0;
       }
       float cmpnb(long* n1, long double num) {
           long n2[lon] = { 0 };
           addnb(bn0, num, n2);
           return cmpbb(n1, n2);
       }

       //大数转普通数(big to num)
       long double bg2nu(long *n) {
           long double n1=0;
           int i;
           for (i = 1;i < lon;i++) { n1 += n[i]*pow(d,*n-i+1); }
           return n1;
       }
       //sin
       long double sinb(long* n, long X[]=0) {
           long double n1 = 0;long n2[lon] = { 0 };
           mtpnb(bpi, 2, n2);
           rmdbb(n, n2, n2);
           n1 = sin(bg2nu(n2));
           if(X)addnb(bn0, sin(bg2nu(n2)), X);
           return n1;
       }

       long double cosb(long* n, long X[] = 0) {
           long double n1 = 0;long n2[lon] = { 0 };
           mtpnb(bpi, 2, n2);
           rmdbb(n, n2, n2);
           n1 = cos(bg2nu(n2));
           if (X)addnb(bn0, cos(bg2nu(n2)), X);
           return n1;
       }

       long double tanb(long* n, long X[] = 0) {
           long double n1 = 0;long n2[lon] = { 0 };
         //  mtpnb(bpi, 2, n2);
           rmdbb(n, bpi, n2);
           n1 = tan(bg2nu(n2));
           if (X)addnb(bn0, tan(bg2nu(n2)), X);
           return n1;
       }

       long double atanb(long* n, long X[] = 0) {
           long double num;
           if (cmpnb(n, pow(10, 18)) > 0) { if (X)ping(bpi, X);return bg2nu(bpi) / 2; }
           num = atan(bg2nu(n));
           if (X) addnb(bn0, num, X);
           return num;
       }

      
       //不完全排列A(n1,n2)n1>n2
       void Abb(long* n1, long* n2, long X[], int n = 1) {
           long* n3, * n4, re[lon] = { 0 ,1 };
           long n5[lon] = { 0 };
           int f = 1;
           if (n) { n3 = n1;n4 = n2; }
           else { n3 = n2;n4 = n1; }
           if (cmpbb(n3, n4) < 0) {copybb(bn0, X);return; }
           if (cmpnb(n3, 0) < 0) { musgb(n3, n3); f *= -1; }
           if (cmpnb(n4, 0) < 0) { musgb(n4, n4); f *= -1; }
           mnsbb(n3, n4, n5);addnb(n5, 1, n5);
           prnum(n5, "n5->");
           ping(n3, n3);ping(n4, n4);
           for (;cmpbb(n5,n3)<=0;addnb(n5, 1, n5)) {
               prnum(re, "re->");
               mtpbb(re, n5, re);
           }
           mtpnb(re,f, X);
       }

       //全排列(full permutation)
       void fpmtb(long*n1,long X[]) {
           Abb(n1, n1, X);
       }
       void Cbb(long* n1, long* n2, long X[], int n = 1) {
           long* n3, * n4, re[3][lon] = { 0 };
           long n5[lon] = { 0 };
           int f = 1;
           if (n) { n3 = n1;n4 = n2; }
           else { n3 = n2;n4 = n1; }
           Abb(n1, n2, re[0]);
           fpmtb(n2, re[1]);
           dvdbb(re[0], re[1], X);
       }

       void lnb(long* n1, long X[]) {
           long n3[lon]={0}, re[lon] = {1 ,1};
           long double num3,num4;
           ping(n1, n3);
           mtpnn(3*log(10), *n3, re);
           *n3 = 0 ;
           addnb(re, log(bg2nu(n3)),X);
       }

       //以10为底的对数
       long double lg(long double num) {
           return(log(num) / log(10));
       }
       void lgb(long* n1, long X[]) {
           long n3[lon] = { 0 }, re[lon] = { 1 ,1 };
           long double num3, num4;
           ping(n1, n3);
           mtpnn(3 * lg(10), *n3, re);
           *n3 = 0;
           addnb(re, lg(bg2nu(n3)), X);
       }

       long double lognn(long double num1, long double num2,  int n = 1,long X[]=0) {
           long double num3;
           num3=n? log(num1) / log(num2):log(num2) / log(num1);
           addnn(0, num3, X);
           return num3;
       }
       void lognb(long* n1, long double num, long X[], int n = 1) {
           long n2[lon] = { 0 };
           lnb(n1, n2);
           if(n)dvdnb(n2, log(num), X);
           else dvdnb(n2, log(num), X,0);
       }
       void logbb(long* n1, long* n2, long X[], int n = 1) {
           long n4[lon] = { 0 },n3[lon] = { 0 };
           lnb(n1, n3);lnb(n2, n4);
           
           if (n)dvdbb(n3, n4, X);
           else dvdbb(n4, n3, X);
       }

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值