/*
  Name: 高精度整数运算改进版
  Copyright:始发于goal00001111的专栏;允许自由转载,但必须注明作者和出处
  Author: goal00001111
  Date: 15-12-08 08:18
  Description:
高精度整数运算:加减乘除,乘方,阶乘 。
上次写了一个用字符串存储高精度整数的四则运算算法,虽然可以实现功能,但时间复杂度和空间复杂度都不够理想,
这次出了个改进版,将原来的用字符串存储改成用整型数组存储,而且改进了乘法,除法和乘方的算法,更快更高效!
*/
#include<iostream>
#include<string>

using namespace std;

const unsigned int MAX = 10000; //整型数组的最大长度
const long long WIDTHMAX = 1000000000; //整型数组val[MAX]的元素上限
const unsigned int WIDTH = 9;  //输出整型数组val[MAX]的元素时的格式宽度,即整型数组val[MAX]的元素的最多位数

typedef struct node
{
    long long val[MAX]; //用来存储高精度整数
    unsigned int size; //整型数组的实际长度
} BigInt;

BigInt StrToBigInt(string s);
void PrintBigInt(const BigInt & a);
int ComPareBigInt(const BigInt & a, const BigInt & b);
BigInt MulBigInt(const BigInt & a, const BigInt & b);
BigInt AddBigInt(const BigInt & a, const BigInt & b);
BigInt SubBigInt(BigInt a, BigInt b);
BigInt DivBigInt(const BigInt & a, const BigInt & b);
BigInt FacBigInt(unsigned int n);
void PowBigInt(BigInt & c, const BigInt & a, unsigned int n);
void PowBigInt_2(BigInt & c, const BigInt & a, unsigned int n);
BigInt HalfBigInt(BigInt a);

int main()
{
    string s;
    BigInt a, b, c;
   
    cin >> s;
    a = StrToBigInt(s);
    cin >> s;
    b = StrToBigInt(s);
   
    cout << "  ";
    PrintBigInt(a);
    cout << "+ ";
    PrintBigInt(b);
    c = AddBigInt(a, b);
    cout << "= ";
    PrintBigInt(c);
    cout << endl;
   
    cout << "  ";
    PrintBigInt(a);
    cout << "- ";
    PrintBigInt(b);
    c = SubBigInt(a, b);
    cout << "= ";
    PrintBigInt(c);
    cout << endl;
   
    cout << "  ";
    PrintBigInt(a);
    cout << "* ";
    PrintBigInt(b);
    c = MulBigInt(a, b);
    cout << "= ";
    PrintBigInt(c);
    cout << endl;
   
    cout << "  ";
    PrintBigInt(a);
    cout << "/ 2 " << endl;
    c = HalfBigInt(a);
    cout << "= ";
    PrintBigInt(c);
    cout << endl;
   
    cout << "  ";
    PrintBigInt(a);
    cout << "/ ";
    PrintBigInt(b);
    c = DivBigInt(a, b);
    cout << "= ";
    PrintBigInt(c);
    cout << endl;
   
    unsigned int n;
    cin >> n;
    //cout << n << "! = ";
//    c = FacBigInt(n);
//    PrintBigInt(c);
//    cout << c.size << endl;
     cout << endl;

    cout << "  ";
    PrintBigInt(a);
    cout << "^" << n << " = ";
    PowBigInt(c, a, n);
    PrintBigInt(c);
    cout << endl;
   
    cout << "  ";
    PrintBigInt(a);
    cout << "^" << n << " = ";
    PowBigInt_2(c, a, n);
    PrintBigInt(c);
    cout << endl;
   
    system("pause");
    return 0;
}
/*
函数名称:PrintBigInt
函数功能:输出用整型数组表示的高精度整数
输入参数:const BigInt & a:用整型数组表示的高精度整数
输出参数:无
*/
void PrintBigInt(const BigInt & a)
{
    cout << a.val[a.size-1];
    for (int i=a.size-2; i>=0; i--)
    {
        unsigned w = WIDTHMAX / 10;
        while (w > 0)
        {
            if (a.val[i] >= w)
                break;
            cout << 0;
            w /= 10;
        }
        cout << a.val[i];
    }
    cout << endl;
}
/*
函数名称:StrToBigInt
函数功能:把元素为数字的字符串转换为用整型数组表示的高精度整数
输入参数:string s:存储数字的字符串
输出参数:BigInt:返回用整型数组表示的高精度整数
*/
BigInt StrToBigInt(string s)
{
    BigInt a;
    a.size = 0;
    int i = s.size();
    unsigned long long sum = 0;
    while ( i>=WIDTH)
    {
        for (int j=i-WIDTH; j<i; j++)
            sum = sum * 10 + (s[j] - '0');
        a.val[a.size++] = sum;
        sum = 0;
        i -= WIDTH;
    }
    if (i > 0)
    {
        for (int j=0; j<i; j++)
            sum = sum * 10 + (s[j] - '0');
        a.val[a.size++] = sum;
    }
    return a;
}
/*
函数名称:AddBigInt
函数功能:高精度整数加法
输入参数:const BigInt & a:用整型数组表示的高精度整数加数
          const BigInt & b:用整型数组表示的高精度整数加数
输出参数:BigInt:返回用整型数组表示的高精度整数和
*/
BigInt AddBigInt(const BigInt & a, const BigInt & b)
{
    //逆序计算a+b,则从低位开始计算
    BigInt c;
    unsigned long long carry = 0;
    unsigned int i = 0;
    c.size = 0;
    while (i < a.size && i < b.size)
    {
        c.val[c.size++] = (a.val[i] + b.val[i] + carry) % WIDTHMAX;
        carry = (a.val[i] + b.val[i] + carry) / WIDTHMAX;
        i++;
    }
    while (i < a.size)
    {
        c.val[c.size++] =  (a.val[i] + carry) % WIDTHMAX;
        carry = (a.val[i] + carry) / WIDTHMAX;
        i++;
    }
    while (i < b.size)
    {
        c.val[c.size++] =  (b.val[i] + carry) % WIDTHMAX;
        carry = (b.val[i] + carry) / WIDTHMAX;
        i++;
    }
    if (carry > 0)
        c.val[c.size++] = carry;
    return c;
}
/*
函数名称:SubBigInt
函数功能:高精度整数减法
输入参数:BigInt a:用整型数组表示的高精度整数被减数
          BigInt b:用整型数组表示的高精度整数减数
输出参数:BigInt:返回用整型数组表示的高精度整数差
*/
BigInt SubBigInt(BigInt a, BigInt b)
{
    BigInt c;
    c.size = 0;
    if (ComPareBigInt(a, b) == 0)
    {
        c.size = 1;
        c.val[0] = 0;
        return c;
    }
    bool flag = false;
    if (ComPareBigInt(a, b) < 0)//交换,并得到一个负号
    {
        flag = true;
        BigInt temp = a;
        a = b;
        b = temp;
    }
    unsigned int i = 0;
    while (i < b.size)
    {
        if (a.val[i] >= b.val[i])
             c.val[c.size++] = a.val[i] - b.val[i];
        else
        {
            a.val[i+1] -= 1;
            c.val[c.size++] = a.val[i] + WIDTHMAX - b.val[i];
        }  
        i++;
    }
    while (i < a.size)
    {
        if (a.val[i] < 0)
        {
            a.val[i+1] -= 1;
            a.val[i] += WIDTHMAX;
        }
        c.val[c.size++] = a.val[i];
        i++;
    }
    //消除多余的高位0
    while (c.val[c.size-1] == 0)
        c.size--;
          
    if (flag)//如果是负数,加上负号
        c.val[c.size-1] = -c.val[c.size-1];
    return c;
}
/*
函数名称:ComPareBigInt
函数功能:比较两个高精度整数的大小
输入参数:BigInt a:用整型数组表示的高精度整数被减数
          BigInt b:用整型数组表示的高精度整数减数
输出参数:int:a > b返回1,a = b返回0,a < b返回-1
*/
int ComPareBigInt(const BigInt & a, const BigInt & b)
{
    if (a.size > b.size)
        return 1;
    if (a.size < b.size)
        return -1;
       
    for (int i=a.size-1; i>=0; i--)
    {
        if (a.val[i] > b.val[i])
            return 1;
        if (a.val[i] < b.val[i])
            return -1;
    }
    return 0;
}
/*
函数名称:MulBigInt
函数功能:高精度整数乘法
输入参数:const BigInt & a:用整型数组表示的高精度整数被乘数
          const BigInt & b:用整型数组表示的高精度整数乘数
输出参数:BigInt:返回用整型数组表示的高精度整数乘积
*/
BigInt MulBigInt(const BigInt & a, const BigInt & b)
{
    if (a.size == 1 && a.val[0] == 0)
        return a;
    if (b.size == 1 && b.val[0] == 0)
        return b;
 
    BigInt c;
    for (int i=0; i<MAX; i++) //全部赋初值为0
        c.val[i] = 0;
    for (int i=0, j=0; i<b.size; i++)
    {
        for (j=0; j<a.size; j++)
        {
            c.val[i+j] += a.val[j] * b.val[i];
            c.val[i+j+1] += c.val[i+j] / WIDTHMAX;
            c.val[i+j] %= WIDTHMAX;
        }
        c.size = i + j;
        if (c.val[c.size] != 0)//最高位有进位
            c.size++;
    }
    return c;
}
/*
老版本:
BigInt MulBigInt2(const BigInt & a, const BigInt & b)
{
    if (a.size == 1 && a.val[0] == 0)
        return a;
    if (b.size == 1 && b.val[0] == 0)
        return b;
 
    BigInt c, tc;
    unsigned long long carry = 0;
    c.size = 0;
    for (int i=0, j=0; i<b.size; i++)
    {
        for (j=0; j<i; j++)//先在临时和tc的低位补足0
            tc.val[j] = 0;
        carry = 0;
        for (j=0; j<a.size; j++)
        {
            tc.val[i+j] = (a.val[j] * b.val[i] + carry) % WIDTHMAX;
            carry = (a.val[j] * b.val[i] + carry) / WIDTHMAX;
        }
        tc.size = i + j;
        if (carry > 0)
            tc.val[tc.size++] = carry;
        //累加到c中
        c = AddBigInt(tc, c);
    }
    return c;
}
*/

/*
函数名称:FacBigInt
函数功能:高精度整数阶乘
输入参数:unsigned int n:正整数
输出参数:BigInt:返回用整型数组表示的高精度整数阶乘
*/
BigInt FacBigInt(unsigned int n)
{
    BigInt s, c;
    c.size = s.size = 1;
    s.val[0] = 1;
    for (unsigned long long i=2; i<=n; i++)
    {
        c.val[0] = i;
        s = MulBigInt(s, c);
    }
    return s;
}

/*
函数名称:PowBigInt
函数功能:递归高效算法求高精度整数幂
输入参数:BigInt & c:存储高精度整数幂的整型数组
          const BigInt & a:用整型数组表示的高精度整数底数
          long long n:  指数
*/
void PowBigInt(BigInt & c, const BigInt & a, unsigned int n)
{
    if (n == 1)
    {
        c = a;
        return ;
    }
    if (n == 0 || (a.size == 1 && a.val[0] == 1))
    {
        c.size = c.val[0] = 1;
        return ; 
    }
   
    PowBigInt(c, a, n/2); //递归求高精度整数幂
   
    c = MulBigInt(c, c); //a^n = a^(n/2)*a^(n/2)*f(a)
    if (n % 2 == 1)      //其中f(a) = 1(n%2==0)或f(a) = a(n%2==1)
        c = MulBigInt(a, c);
}

/*
函数名称:PowBigInt_2
函数功能:非递归高效算法求高精度整数幂
输入参数:BigInt & c:存储高精度整数幂的整型数组
          const BigInt & a:用整型数组表示的高精度整数底数
          long long n:  指数
*/
void PowBigInt_2(BigInt & c, const BigInt & a, unsigned int n)
{
    int stack[MAX] = {0};
    int top = 0;
    while (n > 0) //利用一个栈来存储n的状态:奇数还是偶数
    {
        stack[top++] = n % 2;
        n /= 2;
    }
    c.size = c.val[0] = 1;
    for (int i=top-1; i>=0; i--)
    {
        c = MulBigInt(c, c);  //a^n = a^(n/2)*a^(n/2)*f(a)
        if (stack[i] == 1)   //其中f(a) = 1(n%2==0)或f(a) = a(n%2==1)
            c = MulBigInt(a, c);
    }
}

/*
函数名称:DivBigInt
函数功能:二分法实现高精度整数除法
输入参数:const BigInt & a:用整型数组表示的高精度整数被除数
          const BigInt & b:用整型数组表示的高精度整数除数
输出参数:BigInt:返回用整型数组表示的高精度整数商
*/
BigInt DivBigInt(const BigInt & a, const BigInt & b)
{
    BigInt high, low, mid, one, c;
    if ((a.size == 1 && a.val[0] == 0) || (b.size == 1 && b.val[0] == 0))
    {
        c.size = 1;
        c.val[0] = 0;
        return c;
    }
   
    one.size = 1; //值为1的高精度整数
    one.val[0] = 1;
    high = a;  //上界
    low.size = 1; //下界
    low.val[0] = 0;
    while (ComPareBigInt(low, high) < 0)
    {
        mid = HalfBigInt(AddBigInt(high, low)); //中间数
        c = MulBigInt(mid, b);
        if (ComPareBigInt(c, a) == 0)
            return mid;
        else if (ComPareBigInt(c, a) < 0)
            low = AddBigInt(mid, one);
        else
            high = SubBigInt(mid, one);
    }     
    c = MulBigInt(low, b);
    if (ComPareBigInt(c, a) <= 0)
        return low;
    else
        return SubBigInt(low, one);
}

/*
函数名称:HalfBigInt
函数功能:高精度整数求半
输入参数:BigInt a:用整型数组表示的高精度整数
输出参数:BigInt:返回用整型数组表示的高精度整数的一半
*/
BigInt HalfBigInt(BigInt a)
{
    BigInt c;
    c.size = a.size;
    for (int i=a.size-1; i>0; i--)
    {
        c.val[i] = a.val[i] / 2;  
        if (a.val[i] % 2 == 1)
            a.val[i-1] += WIDTHMAX;
    }
    c.val[0] = a.val[0] / 2;  
    if (c.size > 0 && c.val[c.size-1] == 0)
        c.size--;
       
    return c;
}


Posted on 2008-12-15 17:41 梦想飞扬 阅读(2087) 评论(2)  编辑 收藏 引用

Feedback

# re: 高精度整数运算改进版  回复  更多评论   

2008-12-15 19:06 by 无名
我记得高精度乘法的高效率实现是使用FFT卷积什么的,你可以改进一下

# re: 高精度整数运算改进版  回复  更多评论   

2008-12-25 01:22 by 本拉瘸
用vs2008编译运行马上堆栈溢出.

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理