Exponentiation(求高精度幂)
Time Limit: 500MS | Memory Limit: 10000K | |
Total Submissions: 175340 | Accepted: 42341 |
Description
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
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
Hint
s is a string and n is an integer
C++
while(cin>>s>>n)
{
...
}
c
while(scanf("%s%d",s,&n)==2) //to see if the scanf read in as many items as you want
/*while(scanf(%s%d",s,&n)!=EOF) //this also work */
{
...
}
Source
大意:
对数值很大、精度很高的数进行高精度计算是一类十分常见的问题。比如,对国债进行计算就是属于这类问题。
现在要你解决的问题是:对一个实数R( 0.0 < R < 99.999 ),要求写程序精确计算 R 的 n 次方(Rn),其中n 是整数并且 0 < n <= 25。
Input
T输入包括多组 R 和 n。 R 的值占第 1 到第 6 列,n 的值占第 8 和第 9 列。
Output
对于每组输入,要求输出一行,该行包含精确的 R 的 n 次方。输出需要去掉前导的 0 后不要的 0 。如果输出是整数,不要输出小数点。
解题思路:
(1)pow精度不够
函数原型:double pow( double x, double y );
头文件:math.h/cmath(C++中)
功能:计算x的y次方
返回值:x不能为负数且y为小数,或者x为0且y小于等于0,返回幂指数的结果。
1 #include<math.h> 2 #include<stdio.h> 3 int main() 4 { 5 double x=2.0,y=3.0; 6 printf("%lf raised to %lf is %lf\n",x,y,pow(x,y)); 7 return 0; 8 }
(2)模拟乘法运算过程
必须自己模拟乘法运算过程,进行高精度的运算。
题目把输入的数限制在了6位,即只有5位数字,方便了我们解题。
我们将输入数字,以字符串形式读入,找到小数所在的位数,计算出结果应包含的小数的位数,比如说第一个算式“95.123 12”的小数的位数应该有3*12位。
解题的关键在于进行数据的处理,即模拟整数乘法,使用倒序数组,为什么使用倒序数组呢?我们模拟一下竖式乘法过程,例如:123*123:
1 2 3
x 3
——————
3 6 9
先用个位乘被乘数;
1 2 3
x 2
——————
2 4 6
+ 3 6 9
——————
2 7 12 9
在用十位乘被乘数,并相加。
对大于10的进行进位:2 7 12 9 ==》 2 8 2 9
1 2 3
x 1
——————
1 2 3
+ 2 8 2 9
————————
1 4 11 2 9
在用百位乘被乘数,并相加。
对大于10的进行进位:1 4 11 2 9 ==》 1 5 1 2 9
从上面的乘法竖式中,我们是向前进位,由于我们不知道最后得到的数据的位数,所以采用倒序存储,向后进位;从0位开始乘,结果也从0位开始存,非常方便。这样得出的结果也是倒序的。
为了计算方便,我们不把数字多余的0去掉,而是在最后判断小数点的位置,然后输出该输出的数位。
每次乘法,都是用题目给的r乘上你上一次得出的结果,如果是第一次计算,那么就是r,计算的结果直接加到一个初始化为0的250大小的数组里面,注意是加。乘法的过程很容易模拟出来,就是让乘数让乘数第一位把你的结果的所有位乘一遍,然后再让第二位乘,注意加进数组时,有一个偏移量,乘法竖式都是这么写的,大家体会下。
开一个250的数组m存储结果,并且开一个250的数组jieguo存储中间结果,并且需要一个长度为6的int型数组存储输入的String类型的数据r。
输出结果时要小心,因为数组中存储的数位是倒序的,且没有小数点,需要计算从两边向中间的小数点方向第一个不为0数的位置。
1 #include<iostream>
2 #include<cstring>
3 #include<string>
4 #define MAX 250
5 using namespace std;
6 int main()
7 {
8 string r;//底数
9 int n,dian;
10 short Chengshu[6];
11 short m[MAX],jieguo[MAX];
12 while(cin>>r>>n)
13 {
14 for(int i=0;i<=MAX;i++) {m[i]=jieguo[i]=0;}//初始化
15 for(int j=0;j<6;j++) {Chengshu[j]=0;}
16 dian = 0;//小数点位置
17 size_t pos = r.find(".");
18 if(pos != string::npos) dian = (5-pos)*n;
19 for(int i=5,j=0;i>=0;i--)
20 {//注意此处进行倒序存储
21 if(r[i] != '.') {
22 Chengshu[j] = m[j] = jieguo[j] = r[i]-'0';
23 //此处要给m[]赋值,当n=1时直接输出
24 j++;
25 }
26 }
27 while(n>=2)//当乘幂大于等于2的时候,等于1可直接处理0输出
28 {
29 for(int i=0;i<MAX;++i) m[i]=0;
30 for(int i=0;i<5;i++)
31 {//chengshu[i]
32 for(int j=0;j<MAX;j++)
33 {
34 if(Chengshu[i]==0) break;
35 else{
36 m[i+j] += Chengshu[i]*jieguo[j];
37 //对>9 的进行处理
38 for(int t=i+j;m[t]>9;++t)//处理进位
39 {
40 m[t+1]+=m[t]/10;
41 m[t]=m[t]%10;
42 }
43 }
44 }
45 }
46 //更新被乘数
47 for(int k=0;k<MAX;k++)
48 {
49 jieguo[k] = m[k];
50 }
51 n--;
52 }
53 int first = -1;
54 for(int i=MAX-1;i>=dian;i--)
55 {//从右向左查找第一个不为0的位
56 if(m[i]>0)
57 {
58 first = i;break;
59 }
60 }
61 int last = dian;
62 for(int j=0;j<dian;j++)
63 {//从左向右查找小数点后第一个不为0的位
64 if(m[j]>0) {
65 last = j;break;
66 }
67 }
68
69 if(first != -1)//整数位不全为0
70 {
71 for(int k=first;k>=dian;k--)
72 cout<<m[k];
73 }
74
75 if(last != dian)//有小数位
76 {
77 cout<<".";
78 for(int k=dian-1;k>=last;k--)
79 cout<<m[k];
80 }
81 cout<<endl;
82 }
83 return 0;
84 }
java中有一个类 :java.math.BigDecimal
1 import java.io.*; 2 import java.util.*; 3 import java.math.BigDecimal; 4 5 public class Main 6 { 7 public static void main(String args[])throws Exception 8 { 9 Scanner cin=new Scanner(System.in); 10 while(cin.hasNext()) 11 { 12 BigDecimal r=cin.nextBigDecimal(); 13 int n=cin.nextInt(); 14 r=r.pow(n).stripTrailingZeros();//去掉小数点后面的零 15 String m_string=r.toPlainString();//不带指数段的字符串表示形式 16 if(m_string.charAt(0)=='0') 17 m_string=m_string.substring(1); 18 System.out.println(m_string); 19 } 20 } 21 }