题目:
Description
Input
Output
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思路:
对数值很大、精度很高的数进行高精度计算是一类十分常见的问题。
现在要你解决的问题是:对一个实数R(0.0 < R < 99.999),要求写出程序精确计算R的n次方(Rn),其中n是整数并且0 < n <= 25。
输入包括多组R和n。R的值占第1到第6列,n的值占第8和第9列。
对于每组输入,要求输出一行,该行包含精确的R的n次方。输出需要去掉前导的0和后面不要的0。如果输出是整数,不要输出小数点。
因为c++的double类型根本表示不了这么长的结果,所以得手动写乘方。
我的解法不能算大数相乘的通用算法, 而只是针对题目中(0.0 < R < 99.999)的trick. 因R位数很小, 所以本算法思路是把R扩大倍数而转成整数(99.999 -> 99999), 然后把每次乘积累加到结果数组中。算法比较简单。时间在0ms到16ms之间波动。
代码:
#include <iostream> #include <string> using namespace std; int len; // total length of exponentiation result存储乘方结果的总长度 int product[126] = {0}; //存储结果,最大长度为5*25+1=126(5是99.999有5个数字,25是n的最大值,+1是加的小数点)(可以试一下,99.999的平方是10个数字+一个小数点哦) void multiply(int a[], int n){ int i; int carry = 0; // a carry number in multiplying for (i = 0; i < len; i++){ int temp = a[i]*n + carry; a[i] = temp % 10; carry = temp / 10; } while (carry){ a[i] = carry % 10; i++; carry /= 10; } len = i; } int main(){ int n; // power n char s[6]; // real number R, at most the length is 6 while (cin>>s>>n){ int position=0, i=0, num=0, j=0; for (i=0; i<strlen(s); i++) { if (s[i] == '.'){ position = (strlen(s) - 1 - i) * n; // calculate decimal point position in // in R^n,因为结果数组是倒着放的,所以.的位置要用小数来算 } else{ num = num*10 + s[i] - '0'; // transfer float to integer } } // product calculation product[0]=1; len = 1; for (i = 0; i < n; i++){ multiply(product, num); } // format output if (len <= position){ // product is less than 1 printf("."); // print decimal point for (i=0; i<position-len; i++){ printf("0"); // print zero between decimal point and decimal } j = 0; while (product[j] == 0){ // trim trailing zeros j++; } for (i=len-1; i>=j; i--){ printf("%d", product[i]); } } else{ j=0; while (product[j]==0 && j<position){ // trim trailing zeros j++; } for (i=len-1; i>=j; i--){ if (i+1 == position){ // cause index in C language starts from 0 printf("."); } printf("%d", product[i]); } } printf("\n"); } system("pause"); return 0; }
可是这个是利用了trick,我需要找到一个普遍的解法。于是我就跑去看看别人怎么实现的。
下面是http://www.cnblogs.com/BTMaster/p/3524992.html中的代码。
/* poj 1001 version:1.0 author:Knight Email:[email protected] */ #include<cstdio> #include<cstring> #include<cstdlib> #include<memory.h> using namespace std; char Result[200];//存R^N的结果 //大实数的乘法,乘数为FirMultiplier和SecMultiplier,结果存在Result中 void HigRealMul(char* FirMultiplier, char* SecMultiplier, char* Result); //剔除实数尾部的无效0或小数点 void CutInsignificantTail(char* StrR); //计算小数点在实数中的位数 int CountPointIndex(char* StrR); //删除实数中的小数点,PointIndex为小数点在实数中从右向左数的第几位 void DeletePoint(char* StrR, int PointIndex); int main(void) { char StrR[10];//R对应的字符串 int N; int i; int PointIndex = 0;//记录小数点在实数中从右向左数的第几位,如1.26在第3位,4在第0位 while(scanf("%s%d", StrR, &N) != EOF) { memset(Result, 0, 200); CutInsignificantTail(StrR); PointIndex = CountPointIndex(StrR); DeletePoint(StrR, PointIndex); strcpy(Result, StrR); for (i=2; i<=N; i++) { HigRealMul(Result, StrR, Result); } int Len = strlen(Result); if (Len -(PointIndex - 1) * N < 0) { printf("."); for (i = Len - (PointIndex - 1) * N; i<0; i++) { printf("0"); } } for (i=0; i<Len; i++) { //输出小数点 if (i == Len -(PointIndex - 1) * N) { printf("."); } printf("%c", Result[i]); } printf("\n"); //printf("%s\n", Result); //printf("%d\n", PointIndex); } return 0; } //大实数的乘法,乘数为FirMultiplier和SecMultiplier,结果存在Result中 void HigRealMul(char* FirMultiplier, char* SecMultiplier, char* Result) { char TmpResult[200]; int i,j; int k = -1;//控制TmpResult[]下标 int FirLen = strlen(FirMultiplier); int SecLen = strlen(SecMultiplier); memset(TmpResult, '0', 200); //模拟乘法运算 for (i=SecLen-1; i>=0; i--) { k++; int FirMul; int SecMul = SecMultiplier[i] - '0'; int Carry;//进位 for (j=FirLen-1; j>=0; j--) { FirMul = FirMultiplier[j] - '0'; TmpResult[k + FirLen - 1 - j] += FirMul * SecMul % 10; Carry = FirMul * SecMul / 10 + (TmpResult[k + FirLen - 1 - j] - '0') / 10; TmpResult[k + FirLen - 1 - j] = (TmpResult[k + FirLen - 1 - j] - '0') % 10 + '0'; TmpResult[k + FirLen - j] += Carry; } } //防止某一位的值超过9 for (k=0; k<200; k++) { TmpResult[k + 1] += (TmpResult[k] - '0') / 10; TmpResult[k] = (TmpResult[k] - '0') % 10 + '0'; } //将设置字符串结束符 for (k=199; k>=0; k--) { if ('0' != TmpResult[k - 1]) { TmpResult[k] = '\0'; break; } } //将临时存储的答案TmpResult倒转变成我们熟悉的方式,存到Result中 for (i=strlen(TmpResult)-1,j=0; i>=0; i--,j++) { Result[j] = TmpResult[i]; } Result[j] = '\0'; } //剔除实数尾部的无效0或小数点 void CutInsignificantTail(char* StrR) { int i; int PointIndex = CountPointIndex(StrR); int Len = strlen(StrR); if (0 == PointIndex) { if ('.' == StrR[Len - 1]) { StrR[Len - 1] = '\0'; } return; } for (i=Len-1; i>Len-1-PointIndex; i--) { if ('0' == StrR[i] || '.' == StrR[i]) { StrR[i] = '\0'; } else { return ; } } } //计算小数点在实数中的位数 int CountPointIndex(char* StrR) { int i; int Index = 0; for (i = strlen(StrR); i>=0; i--) { if ('.' == StrR[i]) { break; } else { Index++; } } if (-1 == i) { Index = 0; } return Index; } //删除实数中的小数点 void DeletePoint(char* StrR, int PointIndex) { int i; int Len = strlen(StrR); for (i=strlen(StrR)-PointIndex; i<Len; i++) { StrR[i] = StrR[i+1]; } }
另外,
这个讲得也挺好的,就是代码太啰嗦了。。。 http://xiyueshiyi.blog.163.com/blog/static/203942233201411891210875/
下面引申一些c++的知识:
C++中将string类型转换为int, float, double类型
# 方法一: 使用stringstream
stringstream在int或float类型转换为string类型的方法中已经介绍过, 这里也能用作将string类型转换为常用的数值类型。
Demo:
输出结果:
801 请按任意键继续. . . |
#方法二:使用atoi()、 atil() 、atof()函数 -----------------实际上是char类型向数值类型的转换
注意:使用 atoi 的话,如果 string s 为空,返回值为0.则无法判断s是0还是空
1. atoi(): int atoi ( const char * str );
说明:Parses the C string str interpreting its content as an integral number, which is returned as an int value.
参数:str : C string beginning with the representation of an integral number.
返回值:1. 成功转换显示一个Int类型的值. 2. 不可转换的字符串返回0. 3.如果转换后缓冲区溢出,返回 INT_MAX orINT_MIN
Demo:
输出:
Enter a number: 48 The value entered is : 48 The number convert is: 48 |
2.aotl(): long int atol ( const char * str );
说明:C string str interpreting its content as an integral number, which is returned as a long int value(用法和atoi函数类似,返回值为long int)
3.atof(): double atof ( const char * str );
参数:C string beginning with the representation of a floating-point number.
返回值:1. 转换成功返回doublel类型的值 2.不能转换,返回0.0。 3.越界,返回HUGE_VAL
Demo: