学习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.
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
- 学习ACM之路-大数的幂运算
- ACM 第一天 大数运算
- ACM: 大数运算(正整数)
- 大数运算之大数乘法
- Java学习之ACM中使用大数类的基础方法及入门教程
- 大数运算学习总结
- 大数运算之快速幂算法
- C++之运算符的重载实现大数的运算
- 大数运算之乘法
- 最大公约数之大数运算
- 大数运算之阶乘
- 大数运算之加法
- 大数运算之加减乘除
- ACM大数的处理
- java在acm中大数运算教程
- java在acm中大数运算教程
- JAVA在ACM中大数运算教程
- java在acm中大数运算教程
- android studio关于build/outputs/apk/中apk或arr或jar无法删除的解决方法
- 个人记事本
- iOS SVProgressHUD 简单使用
- 0708学习记录
- css3的3D图片旋转
- 学习ACM之路-大数的幂运算
- Java基础之多线程断点下载
- C# 刷新win7桌面
- Java线程经典面试题
- bnuoj_4049 四叉树
- SPOJ 375 树链剖分
- C语言link()函数:建立文件连接
- Unity5-ABSystem(一):AssetBundle原理
- Android清除本地数据缓存代码案例