题目:
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
#include
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=j; i--){
printf("%d", product[i]);
}
}
else{
j=0;
while (product[j]==0 && j=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
#include
#include
#include
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=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
另外,
这个讲得也挺好的,就是代码太啰嗦了。。。 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: