Road of poj-1001

来源:互联网 发布:微信点赞软件免费 编辑:程序博客网 时间:2024/06/09 17:21

Description

对数值很大、精度很高的数进行高精度计算是一类十分常见的问题。比如,对国债进行计算就是属于这类问题。

现在要你解决的问题是:对一个实数R( 0.0 < R < 99.999 ),要求写程序精确计算 R 的 n 次方(Rn),其中n 是整数并且 0 < n <= 25。

Input

输入包括多组 R 和 n。 R 的值占第 1 到第 6 列,n 的值占第 8 和第 9 列。

Output

对于每组输入,要求输出一行,该行包含精确的 R 的 n 次方。输出需要去掉前导的 0 后不要的 0 。如果输出是整数,不要输出小数点。

思路

将小数用数组存储,数组下标为10的幂值,即数组a第i项表示a[i]*10^i,当做整数进行运算。小数点位置可以根据输入时小数点位置进行确定。

代码

#include <iostream>#include <cstring>#define MAX 150     //(100000)^25 = 10^150using namespace std;int main(){    char s[6] = {'\0'};    char outstr[MAX] = {'\0'};  //输出字符串    int n = 0;  //幂值    int pointpos = 0;  //小数点位置,缺省为0    int out[MAX] = {0};  //暂存每次计算结果    int num1[MAX] = {0};  //被乘数,类似于除法定义的‘被除数’    int num2[MAX] = {0};  //乘数,类似于除法定义的‘除数’    while(cin >> s >> n)    {        //分析输入的数值,计算出小数位数,将小数存为整数        for(int i = 0, j = 0 ; i < 6 ; i++, j++)        {            if(s[i] == '.')            {                pointpos = n*(5-i);  //记录有多少位小数                j--;            }            else            {                //这里已经将小数存为整数                num2[4-j] = s[i] - '0';  //因为s[0]对应着num2[4]            }        }        memcpy(num1, num2, sizeof(int)*MAX);        for(int i = 1 ; i<n ; i++)  //第一层循环记录乘方次数        {            for(int j = 0 ; j<MAX ; j++)  //第二层循环遍历被乘数数组            {                for(int k = 0 ; k<MAX ; k++)  //第三层循环遍历乘数数组                {                    //核心算法是多项式相乘                    out[j+k] = out[j+k] + num1[j] * num2[k];                    //一旦大于等于10,向后进1位                    for(int l = j+k ; l<MAX ; l++)                    {                        if(out[l] >= 10)                        {                            out[l+1] += out[l]/10;                            out[l] = out[l]%10;                         }                    }                }            }            memcpy(num1, out, sizeof(int)*MAX);            //将计算得到的out赋给num1,准备下一次计算。            memset(out, 0, MAX*sizeof(int));            //将out清空,用来存放下一次的中间计算结果。            //这样也就导致最后的计算结果存放在num1中        }        int flag = 0; //num1从后向前遍历,跳过整数的前置零        for(int i = MAX-1, j = 0 ; i>=0 ; i--)        {            if(num1[i] == 0 && flag == 0 && i != pointpos - 1)            {                continue;            }            else            {                if( i == pointpos - 1)  //到达小数点位置                {                    outstr[j++] = '.';                }                outstr[j++] = num1[i] + '0';                flag = 1;             }        }        //outstr从后向前遍历,去除小数的后置零        for(int i = (signed)strlen(outstr)-1 ; i>=0 ; i--)        {            if(outstr[i] == '0')            {                outstr[i] = '\0';                if(outstr[i-1] == '.') //结果为整数,将小数点赋为\0                {                    outstr[i-1] = '\0';                    break;                }            }            else            {                break;            }        }        cout << outstr << endl;        //清空num1,num2,outstr,out在之前已经清空。        memset(num1, 0, sizeof(int)*MAX);        memset(num2, 0, sizeof(int)*MAX);        memset(outstr, '\0', sizeof(char)*MAX);    }    return 0;}

注意事项

1、前置零后置零的处理。
2、整数的处理。
3、每次输入处理后一定要及时进行清零。

总结

总体来讲思路比较清楚,实现起来不困难,多项式相乘的算法可能算一个不大的点。主要的困难在于如何把所有情况考虑在内,需要好好构思思路以及测试数据。ps. 这个多项式相乘写的巨丑无比,之后应该会进行改写~