[POJ][1001]Exponentiation

Description

Problems involving the computation of exact values of very large magnitude and precision are common. For example, the computation of the national debt is a taxing experience for many computer systems. 

This problem requires that you write a program to compute the exact value of R n where R is a real number ( 0.0 < R < 99.999 ) and n is an integer such that 0 < n <= 25.

Input

The input will consist of a set of pairs of values for R and n. The R value will occupy columns 1 through 6, and the n value will be in columns 8 and 9.

Output

The output will consist of one line for each line of input giving the exact value of R^n. Leading zeros should be suppressed in the output. Insignificant trailing zeros must not be printed. Don't print the decimal point if the result is an integer.

Sample Input

95.123 12
0.4321 20
5.1234 15
6.7592  9
98.999 10
1.0100 12

Sample Output

548815620517731830194541.899025343415715973535967221869852721
.00000005148554641076956121994511276767154838481760200726351203835429763013462401
43992025569.928573701266488041146654993318703707511666295476720493953024
29448126.764121021618164430206909037173276672
90429072743629540498.107596019456651774561044010001
1.126825030131969720661201
 

这道题目考查高精度乘法的计算。

要解决这道题目并不能使用cmath里的pow函数,而必须自己模拟乘法的计算过程,以实现高精度结果的输出。

所幸输入的底数一定是5位数,这给我们创造了一点方便。

我们可以将底数以字符串的形式读入,然后计算出结果中小数点应该在多少位,比如第一个结果应该是3*12=36。

关键的部分在于数据的处理,这里我的办法是倒序去掉小数点逐位存储,比如95.123,最后应该是用一个大小为5的数组存储为[3][2][1][5][9],每个单元只存一个数位。这里涉及到存储类型的问题,为了计算方便,最好用short类型的数组。

存储结果的数组需要开到150,我没有精确计算,大概是这么大,我选择160。

为了计算方便,我们不把数字多余的0去掉,而是在最后判断小数点的位置,然后输出该输出的数位。

每次乘法,都是用题目给的r乘上你上一次得出的结果,如果是第一次计算,那么就是r,计算的结果直接加到一个初始化为0的160大小的数组里面,注意是加。乘法的过程很容易模拟出来,就是让乘数让乘数第一位把你的结果的所有位乘一遍,然后再让第二位乘,注意加进数组时,有一个偏移量,乘法竖式都是这么写的,大家体会下。

为什么使用倒序存储的数组呢,想想上面对竖式的模拟就很容易明白了,从0位开始乘,结果也从0位开始存,非常方便。这样得出的结果也是倒序的。

输出结果时要小心,因为数组中存储的数位是倒序的,且没有小数点,需要计算从两边向中间的小数点方向第一个不为0数的位置,这是为了避免输出不必要的0而导致WA。

给出一个计算过程演示:

比如输入为1.0002 3

   20001

× 2

------------

  40002

此时结果数组中存储的是40002

   20001

×    0

------------

  40002

     00000

此时结果数组中存储的是40002

中间省略两步

   20001

×          1

 ------------

   40002

     00000

       00000

         00000

            20001

此时结果数组中存储的是400040001

   400040001

× 2

------------------

这里我就不计算了,最后结果数组里面存的是8000210060001

根据4*3=12,可以知道小数点应插在12号位,也就是11号位后面

800021006000.1

两边向中间,第一个不为0的数恰好就是两边,输出为

1.000600120008

最后给出AC代码,注意POJ里面,如果选择C++,则要#include<string>,这里的代码是G++下AC的,在C++下会CE

#include<iostream>
#include<cstring>
using namespace std;
int main()
{
    string r;
    int n,dianwei;
    const int R_LEN=160;
    short result[R_LEN],jieguo[R_LEN],chengshu[6];
    while(cin>>r>>n)
    {
        int len=0;
        for(int i=0;i<R_LEN;++i) jieguo[i]=result[i]=0;//初始化为0
        for(int i=0;i<6;++i) chengshu[i]=0;
        dianwei = 0;
        size_t pos = r.find(".");
        if(pos != string::npos) dianwei=(5-pos)*n;
        for(int i=5,j=0;i>=0;--i)
        {
            if(r[i]!='.')
            {
                jieguo[j]=result[j]=chengshu[j]=r[i]-'0';//提取数位
                ++j;
            }
        }
        while(n>=2)//指数大于等于2的时候计算,否则就是直接去除多余0输出了
        {
            --n;
            for(int i=0;i<R_LEN;++i) result[i]=0;
            for(int i=0;i<5;++i)//乘数数位循环
            {
                int c;
                for(int j=0;j<R_LEN;++j)//被乘数数位循环
                {
                    if(chengshu[i]==0) break;
                    c=chengshu[i]*jieguo[j];
                    result[i+j]+=c;
                    for(int t=i+j;result[t]>9;++t)//处理进位
                    {
                        result[t+1]+=result[t]/10;
                        result[t]=result[t]%10;
                    }
                }
            }
            for(int i=0;i<R_LEN;++i) jieguo[i]=result[i];//结果转存,以便下一次循环计算
        }
        int firstindex=-1;
        for(int i=R_LEN-1;i>=dianwei;--i)//从右往左查找小数点前第一个不为0的数
        {
            if(result[i]>0)
            {
                firstindex=i;
                break;
            }
        }
        int lastindex=-1;
        for(int i=0;i<dianwei;++i)//从左往右查找小数点前第一个不为0的数
        {
            if(result[i]>0)
            {
                lastindex=i;
                break;
            }
        }
        if(firstindex!=-1)//输出小数点前的部分
        {
            while(firstindex>=dianwei)
            {
                cout<<result[firstindex];
                --firstindex;
            }
        }
        if(lastindex!=-1)//如果有小数部分,先输出小数点,再输出小数部分
        {
            cout<<'.';
            --dianwei;
            while(dianwei>=lastindex)
            {
                cout<<result[dianwei];
                --dianwei;
            }
        }
        cout<<endl;
    }
}


  • 17
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值