学习ACM之路-大数的幂运算

来源:互联网 发布:三峡大学网络教育 编辑:程序博客网 时间:2024/05/29 14:53

附上北大OJ上的题目1001:

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 Rn 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 120.4321 205.1234 156.7592  998.999 101.0100 12

Sample Output

548815620517731830194541.899025343415715973535967221869852721.0000000514855464107695612199451127676715483848176020072635120383542976301346240143992025569.92857370126648804114665499331870370751166629547672049395302429448126.76412102161816443020690903717327667290429072743629540498.1075960194566517745610440100011.126825030131969720661201
源代码来自于 http://blog.csdn.net/neoxuhaotian/article/details/6159522,谢谢这位大神,我先进行了学习和理解,并在其基础上做了修改,使得更容易阅读和理解。

由于我添加的注释较多,具体过程便不细说,主要说下注意事项。

1、相乘的过程中注意进行数据类型的转换

2、申请的内存块记得在合适的位置释放掉

3、注意数组越界问题

4、注意计算小数点位置的问题


#include<iostream>  #include<cstring>  using namespace std;  int main()  {      char *result;      char *multiply(char *m1,char *m2);//高精度乘法      char source[1000];  //保存源数据数     int n;    //保存幂     while(cin>>source>>n)  //输入     {          int sign=0;//是否有小数点 int sourceLength = strlen(source);//源数据长度 int radixPoint = 0;//小数点的索引         for(int i=0; i<sourceLength; i++)         {     if(source[i]=='.')              {                  sign=1;  //有小数点                 radixPoint = i;  //小数点的索引                 break;              }          }        if(sign == 0)  //没有小数点的情况          {              if(n==0)//指数为0              {cout<<'1'<<endl;  }               else if(n == 1) //指数为1              {cout << source << endl;  }               else  //指数>=2              {                  result=multiply(source,source);                                  for(int i=3; i<=n; i++){char *temp = result;  //暂存指针 result=multiply(result,source);  delete []temp;  //释放不用的内存 }                     cout<< result << endl;  //输出结果                 delete []result;//释放             }          }          else if(sign == 1)//有小数点的情况  ,包括xxxx.0000(如1.00)这种情况         {              if(radixPoint==1 && source[0]=='0')  //小数点前面为0的情况形如0.xxxxxxx              {              int lastValidIndex = sourceLength-1;                  while(source[lastValidIndex]=='0' && lastValidIndex>radixPoint)//去掉后面没有意义的0                  {lastValidIndex--;  }  //如果最后没有有效数字,lastValidIndex =  radixPoint            if(n == 0) //指数为0                  {cout<<'1'<<endl;  }else if(n == 1) //指数为1                  {  //lastValidIndex 为原数据从后面数起,第一个非0数的索引                     for(int i=radixPoint; i<=lastValidIndex; i++)                      {cout << source[i];  //输出 }                     cout<<endl;                  }                 else if(n >= 2)//指数大于等于2                  {                  int firstValidIndex;//小数点后面第一位非0数字的索引 int validIndex=0;  //有效数字数组的索引                 char validNumber[10000];  //保存小数点后面的有效数字                 for(int i=2; i<sourceLength; i++)                  {                      if(source[i] != '0' )  //小数部分距离小数点最近的一个非0数的位置                    {                          firstValidIndex = i;                          break;                      }                  }                  for(int i=firstValidIndex; i<=lastValidIndex; i++)                 {                validNumber[validIndex] = source[i];                   validIndex ++;}                 validNumber[validIndex] = '\0';                                    result = multiply(validNumber,validNumber);                      for(int i=3;i<=n;i++)   //做高精度乘法                      {                    char *temp = result;result = multiply(result,validNumber);  delete []temp;}                     int resultLength = strlen(result);//相乘结果长度                int zeroAmount = (lastValidIndex+1-2)*n-resultLength;  //计算小数点后和小数点后第一个非0数之间0的个数                     cout << ".";                                          for(int i=0; i<zeroAmount; i++)                      {                    cout << '0';//输出小数点后面的0 }      int resultReverseIndex = resultLength-1;//对result反序进行遍历                     while(result[resultReverseIndex]=='0' && resultReverseIndex>=0)//除去后面无意义的0                      {resultReverseIndex--; }    //resultReverseIndex = 小数部分最后一位非0数的索引                     for(int i=0; i<=resultReverseIndex; i++)                      {                    cout << result[i];}                          cout << endl;                  }              }              else//非0.xxxxxx这种情况             {                  if(n == 0) //指数为0                  {                cout<<'1'<<endl;  }                else if(n == 1)//指数为1                  {                      int sourceReverseIndex = sourceLength-1;                    //小数点的位置在radixPoint中保存                                             while(source[sourceReverseIndex]=='0' && sourceReverseIndex > radixPoint)//除去无意义的零                      {                    sourceReverseIndex--;}//sourceReverseIndex = 小数点后面最后一个非0数的索引 或者是小数点                     for(int i=0; i<radixPoint; i++) //输出小数点前面的部分 {cout << source[i];}                      //判断是否xxxx.00000---这种情况                     if(sourceReverseIndex != radixPoint)//不是                     {                          cout<<'.';                          //输出小数部分                         for(int i=radixPoint+1; i<=sourceReverseIndex; i++){cout << source[i];}                      } cout << endl;                 }                  else if(n >= 2) //指数大于等于2                  {                      char integer[1000];//将整个数据小数点移走(相当于原数*10的小数部分位数次方) int integerIndex = 0;  int sourceLastValidIndex = sourceLength - 1;while(source[sourceLastValidIndex] == '0' && sourceLastValidIndex > radixPoint){sourceLastValidIndex -- ;}                    for(int i=0; i<=sourceLastValidIndex; i++)//用integer数组来保存转化后的整数                      {if(source[i] != '.') {integer[integerIndex] = source[i];  integerIndex++;} }                       integer[integerIndex] = '\0';                                          result=multiply(integer,integer);//高精度乘法                      for(int i=3;i<=n;i++)                      {                    result=multiply(result,integer); }                                        int resultLength = strlen(result);                                          int decimalLength = ((sourceLastValidIndex+1) - (radixPoint+1))*n; //计算小数部分长度                     //如果最后相乘的结果是123456,小数点在4,5之间,radixPointInResult = 5的索引                     int radixPointInResult = resultLength-decimalLength;                                        for(int i=0; i<radixPointInResult; i++)  //输出小数点前面的整数部分                     {                    cout << result[i];  }                                           int resultReverseIndex = resultLength-1;                                        while(result[resultReverseIndex]=='0' && resultReverseIndex >= radixPointInResult)//除去小数点后面的无意义的0 {resultReverseIndex--;} //resultReverseIndex = 整数部分的最后一位的索引 || 小数部分                     if(resultReverseIndex >= radixPointInResult)                      {cout<<'.';  //小数点后面还有数字 for(int i=radixPointInResult; i<=resultReverseIndex; i++)                      {                    cout << result[i];  }}                       cout << endl;                  }              }          }      }      return 0;  }  char *multiply(char *m1,char *m2)//以下为高精度乘法的所有函数  m1*m2 {      int *str2int(char *strOfInt);  //字符串转换为整数,存放在连续内存块上,返回首地址     char *int2str(int *intOfStr,int interimLength);  //和str2int相反     int transInterResu(int *interimResult,int lengthSum); //处理相乘的结果          int length1=strlen(m1); //m1长度 int length2=strlen(m2);  //m2长度 int lengthSum=length1+length2;    //总长度  int *t1,*t2;int *interimResult; //相乘后的中间结果内存块地址     t1=str2int(m1);  //t1保存m1转化为整型后内存块的首地址     t2=str2int(m2);  //t2保存m2转化为整型后内存块的首地址         interimResult = new int[(lengthSum+1)*sizeof(int)];  //申请空间         for(int i=0; i<=lengthSum; i++)      {interimResult[i] = 0;  //初始化 }        for(int i=0; i<length1; i++)      {for(int j=0; j<length2; j++)  {interimResult[i+j] += t1[i]*t2[j];  //从低到高逐位相乘  }  }   //处理中间结果 int interimLength = transInterResu(interimResult,lengthSum);//转换为字符串型     return int2str(interimResult,interimLength);  }  int *str2int(char *strOfInt)  {      int length = strlen(strOfInt);  //长度     int *intOfStr = new int[(length+1)*sizeof(int)];  //申请空间     for(int i=0;i<length;i++)      {intOfStr[i] = strOfInt[length-1-i]-'0';  //转化为整数 }       return intOfStr;  }  int transInterResu(int *interimResult,int lengthSum)  //interimResult 是整型内存块的地址,lengthSum总长度{  int interimReverseIndex = lengthSum - 1;//反向索引 //从高到低,找到最高的一位的边界,如果相乘的中间结果为全0,那么结果interimReverseIndex = 0     while(interimReverseIndex>0 && interimResult[interimReverseIndex]==0)       {interimReverseIndex--; }             for(int i=0; i<=interimReverseIndex; i++)      {    if(interimResult[i] >= 10)   //产生进位         {          int carry = interimResult[i] / 10;   //进位             interimResult[i+1] += carry;  //向高位进位             interimResult[i] %= 10;   //余数         } }int lengthAfterTrans = interimReverseIndex + 1;    if(interimResult[interimReverseIndex+1] != 0) //向原值为0的最高位进位了 { lengthAfterTrans ++;}              return lengthAfterTrans;  //返回有效长度 }  char *int2str(int *intOfStr,int interimLength)  {      char *strOfInt = new char[(interimLength+1)*sizeof(char)];      for(int i=0; i<interimLength/2; i++) {strOfInt[i] = intOfStr[interimLength-1-i] + '0';  //转换为字符 }             strOfInt[interimLength] = '\0';  //结束符     delete []intOfStr;   //释放整型内存块     return strOfInt;  }  






0 0
原创粉丝点击