Problem Address:http://poj.org/problem?id=1001
【前言】
想随便找到题,于是翻出了收藏夹里的这道题。
嗯,高精度。
记得之前写过一个高精度乘法,但是不知道为什么错。
现在又一次面临高精度乘法。
还好最近刚写过一次,好似没出错,所以现在想试一下。
WA了一次,看discuss发现所给数字只是占了六位。改之。
同时发现了一个bug,于是debug。
然后AC。
【思路】
高精度。
先记录小数点的位数。再以整数求幂。最后再把小数点添加上去。
可以使用快速幂的方法。
但是,里面有很多需要注意的地方。
(1)所给小数只是占六个位,并不是一定是六个位都占满。同时可能存在没有小数点的情况。
(2)该小数可能是”.123","123.“,“0.123”等各种情况。
(3)其中的R和n均不为零。结果不可能为零。
(4)结果中可能存在前缀零个数很多的情况。多余的零要去掉,包括前缀零和后缀零。
(5)当没有小数或者整数部分时,应这样表示:“0.123” 表示为 “.123”,“123." 表示为 “123”。
【代码】
#include <iostream>
#include <cstring>
using namespace std;
const int size = 200;
struct num
{
int n[size];
int len;
num()
{
memset(n, 0, sizeof(n));
len = 1;
}
};
void multiply(num &t, num s)//单个乘法
{
int i,j;
num a;
for (i=0; i<t.len; i++)
{
for (j=0; j<s.len; j++)
{
a.n[i+j] += t.n[i] * s.n[j];
}
}
for (i=0; i<size-1; i++)
{
if (a.n[i]>=10)
{
a.n[i+1] += a.n[i]/10;
a.n[i] = a.n[i]%10;
}
}
for (i=size-1; i>=0; i--)
{
if (a.n[i]!=0) break;
}
a.len = i+1;
if (a.len==0)
a.len = 1;
for (i=0; i<size; i++)
{
t.n[i] = a.n[i];
}
t.len = a.len;
}
void output(num a, int d)//输出数字
{
int i,j;
if (a.len<=d) a.len = d+1;
for (i=a.len-1; i>=d; i--)
{
if (a.n[i]!=0) break;
}
for ( ; i>=d; i--)
{
printf("%d", a.n[i]);
}
for (j=0; j<d; j++)
{
if (a.n[j]!=0) break;
}
if (j<d)
{
printf(".");
for ( ; i>=j; i--)
{
printf("%d", a.n[i]);
}
}
printf("\n");
}
num BigIntPow(num a, int n)//快速幂
{
num t;
t.n[0] = 1;
while(n>0)
{
if (n&1) multiply(t, a);
multiply(a, a);
n >>= 1;
}
return t;
}
int main()
{
char temp[10] = "";
int n;
int i,j;
int decimal;
int len;
while(scanf("%s %d", temp, &n)!=EOF)
{
num t;
len = strlen(temp);//以下处理读入的数字
for (i=len-1; i>=0; i--)
{
if (temp[i]=='.') break;
}
if (i>=0)
{
decimal = (len-i-1)*n;
for (i=len-1,j=0; i>=0; i--)
{
if (temp[i]=='.') continue;
t.n[j] = temp[i] - '0';
j++;
}
t.len = len-1;
}
else
{
decimal = 0;
for (i=len-1,j=0; i>=0; i--,j++)
{
t.n[j] = temp[i] - '0';
}
t.len = len;
}
output(BigIntPow(t, n), decimal);
memset(temp, 0, sizeof(temp));//存储空间清零,可以省去
}
return 0;
}