/*
  Name: 高精度运算
  Copyright:始发于goal00001111的专栏;允许自由转载,但必须注明作者和出处
  Author: goal00001111
  Date: 01-12-08 15:04
  Description:
高精度运算:加减乘除,乘方,阶乘
*/

#include<iostream>
#include<string>

using namespace std;

void Reverse(string & str);
void AddInt(string & c, string a, string b);
void SubInt(string & c, string a, string b);
void MulInt(string & c, string a, string b);
void JieCHInt(string & c, string b);
void DivInt(string & c, string a, string b);
void PowInt(string & c, string a, string b);

int main()
{
    string a, b, c;
    cin >> a >> b;
   
    AddInt(c, a, b);
    cout << a << " + ";
    cout << b << " = " << endl;
    cout << c << endl;
   
    SubInt(c, a, b);
    cout << a << " - ";
    cout << b << " = " << endl;
    cout << c << endl;

    MulInt(c, a, b);
    cout << a << " * ";
    cout << b << " = " << endl;
    cout << c << endl;

//   
//    cin >> b;
//    JieCHInt(c, b);
//    cout << b << " ! = " << endl;
//    cout << c << endl;
//   
    DivInt(c, a, b);
    cout << a << " / ";
    cout << b << " = " << endl;
    cout << c << endl;
   
//    PowInt(c, a, b);
//    cout << a << " ^ ";
//    cout << b << " = " << endl;
//    cout << c << endl;
   
    system("pause");
    return 0;
}

void Reverse(string & str)
{
    int left, right;
    left = 0; right = str.size()-1;
    while (left < right)
    {
        char ch = str[left];
        str[left] = str[right];
        str[right] = ch;
        left++; right--;
    }
}

void AddInt(string & c, string a, string b)//模仿递增向量的合并方法
{
    c.resize(0);
    Reverse(a);
    Reverse(b);
   
    //逆序计算a+b,则从低位开始计算
    int i, carry;
    i = carry = 0;
    while (i < a.size() && i < b.size())
    {
        c    += (a[i]-'0' + b[i]-'0' + carry) % 10 + '0';
        carry = (a[i]-'0' + b[i]-'0' + carry) / 10;
        i++;
    }
    while (i < a.size())
    {
        c    += (a[i]-'0' + carry) % 10 + '0';
        carry = (a[i]-'0' + carry) / 10;
        i++;
    }
    while (i < b.size())
    {
        c    += (b[i]-'0' + carry) % 10 + '0';
        carry = (b[i]-'0' + carry) / 10;
        i++;
    }
    while (carry > 0)//计算进位部分
    {
        c     += carry % 10 + '0';
        carry /= 10;
    }
    i = c.size() - 1;
    while (c[i] == '0')//消除多余的高位0
    {
        i--;
    }
    c = c.substr(0, i+1);
    Reverse(c);
}

void SubInt(string & c, string a, string b)//模仿递增向量的合并方法
{
    c.resize(0);
   
    if (a == b)
    {
        c += '0';
        return ;
    }
   
    bool flag = false;
    if (a.size() < b.size() || (a.size() == b.size() && a < b))//交换,并得到一个负号
    {
        flag = true;
        string temp = a;
        a = b;
        b = temp;
    }
   
    Reverse(a);
    Reverse(b); ;
    int i = 0;
    while (i < b.size())
    {
        if (a[i] >= b[i])
             c += a[i] - b[i] + '0';
        else
        {
            a[i+1] -= 1;
            c      += a[i] + 10 - b[i] + '0';
        }  
        i++;
    }
    while (i < a.size())
    {
        if (a[i] < '0')
        {
            a[i+1] -= 1;
            a[i] += 10;
        }
        c += a[i];
        i++;
    }
    i = c.size() - 1;
    while (c[i] == '0')//消除多余的高位0
    {
        i--;
    }
    c = c.substr(0, i+1);
    if (flag)
        c += '-';
    Reverse(c);
}

void MulInt(string & c, string a, string b)
{
    c.resize(0);
    if (a == "0" || b == "0")
    {
        c += '0';
        return ;
    }
   
    Reverse(a);
    Reverse(b);
    string ta, tb, tc;
    int carry = 0;
    for (int i=0; i<b.size(); i++)
    {
        tc.resize(0);
        for (int j=0; j<i; j++)//先在临时和tc的低位补足0
            tc += '0';
       
        carry = 0;
        for (int j=0; j<a.size(); j++)
        {
            tc   += ((a[j]-'0') * (b[i]-'0') + carry) % 10 + '0';
            carry = ((a[j]-'0') * (b[i]-'0') + carry) / 10;
        }
        while (carry > 0)//计算进位部分
        {
            tc    += carry % 10 + '0';
            carry /= 10;
        }
        //累加到c中
        ta = c;
        Reverse(ta);
        Reverse(tc);
        AddInt(c, ta, tc);
        Reverse(c);
        //消除多余的高位0
        int pos = c.size() - 1;
        while (c[pos] == '0')
        {
            pos--;
        }
        c = c.substr(0, pos+1);
    }
   
    Reverse(c);
}

void JieCHInt(string & c, string b)
{
    string tb = "2";
    c = "1";
    while (tb.size() < b.size() || (tb.size() == b.size() && tb <= b))
    {
        MulInt(c, c, tb);
        AddInt(tb, tb, "1");
    }
}

void DivInt(string & c, string a, string b)
{
    c.resize(0);
    if (a == "0" || b == "0")
    {
        c += '0';
        return ;
    }
   
    string copyA = a;//存储a的值,之后a的值会变化
    while (a == b || a.size() > b.size() || (a.size() == b.size() && a > b))//直到余数小于除数
    {
        for (int n=1; n<=a.size(); n++)
        {
            string ta = a.substr(0, n);//提取不小于除数的部分被除数
            if (ta == "0") //是0直接跳过
            {
                c += '0';
                a = a.substr(n, a.size()-n);
                break;
            }
            if (ta == b)//相等,商为1,被除数去掉前n位
            {
                c += '1';
                a = a.substr(n, a.size()-n);
                break;
            }
            else if (ta.size() > b.size() || (ta.size() == b.size() && ta > b))//被除数不小于除数
            {
                char i = 0;//记录商
                string tb = b;
                while (ta.size() > tb.size() || (ta.size() == tb.size() && ta > tb))//用多次减法实现除法运算
                {
                    AddInt(tb, tb, b);
                    i++;
                }

                if (ta == tb)//整除
                {
                    c += i + '1';
                    a = a.substr(n, a.size()-n);
                    break;
                }
                else//余数不为0
                {
                    c += i + '0';
                    int pos = ta.size(); //记录上一次被除数的增添位置
                    SubInt(tb, tb, b);//再减回去,使tb < ta
                    SubInt(ta, ta, tb);//获取余数
                    n = ta.size();//下一次增添被除数位置
                    ta += a.substr(pos, a.size()-pos);//得到新的被除数
                    a = ta;
                }
            }
            else//被除数小于除数,商为0
            {
                c += '0';
            }
        }
    }
   
    while (copyA.size() > c.size())//补足低位的0
        c += '0';
   
    //消除多余的高位0
    int pos = 0;
    while (pos < c.size() && c[pos] == '0')
    {
        pos++;
    }
    c = c.substr(pos, c.size()-pos);
   
    if (c.size() == 0)//商为0
        c = "0";
}

void PowInt(string & c, string a, string b)
{
    c.resize(0);
    if (a == "0")
    {
        c = "0";
        return ;
    }
   if (b == "0")
   {
        c = "1";
        return ;  
   }
   if (b == "1")
   {
        c = a;
        return ;  
   }
  
   string tb;
   DivInt(tb, b, "2");
   PowInt(c, a, tb);
   MulInt(c, c, c);
  
   if ((b[b.size()-1]-'0')%2 == 1)
       MulInt(c, c, a);
}


Posted on 2008-12-01 15:09 梦想飞扬 阅读(569) 评论(3)  编辑 收藏 引用

Feedback

# re: 高精度运算  回复  更多评论   

2008-12-12 21:33 by 本拉瘸
拜读,不过我想写成类更好一点.

# re: 高精度运算  回复  更多评论   

2008-12-13 14:00 by 本拉瘸
不支持负数的运算是一个瑕疵.也就是多点flag和a.at(0),b.at(0).

# re: 高精度运算  回复  更多评论   

2008-12-13 18:37 by 本拉瘸
高精度乘除法有问题.
比如 99 20

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