高精度POJ1001

今天看到这道题了 poj1001 题目地址是http://bailian.openjudge.cn/practice/1001/

英文看得懂,可是算法不明白,所以转别人的文章,留着给学生看看:乔高建(高精度

 

  • 解题思路

    这道题属于高精度乘法运算,要求输入一个实数R一个指数N,求实数R的N次方,由于R有5个数位,而N又特别大,因此用C++自带的数据类型放不下.
    解题思路是通过数组储存每次乘积结果和底数的每一位数,按照乘法上下算式的方法,计算底数乘数数组每一位与临时结果数组的每一位的乘积,(因为算术运算中是从数的后面往前算的,这里存储数时要先倒序,输出时再颠倒过来,)然后偏移相加,判断得出的临时结果数组的每一位是否大于9,通过除法和取模实现进位和取余.至此得出一个有很多无效数位的结果数组(很多无效的0).
    最后判断结果数组的每一位是否为0,先输出小数点前面的数,后输出小数点后面的数,最终得出乘法结果.
    这个题目实际上考的是高精度乘法,高精度的其他运算和这个差不多,原理都是一样的.
    解题思路

  • 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.

  • 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 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

    If you don't know how to determine wheather encounted the end of input:
    s is a string and n is an integer

  • SourceCode

#include<iostream>
#include<cstring> using namespace std; int main() { string r; //底数 int n,dianwei; //指数,小数点位置 const int len=200; //数位长度 short result[len],jieguo[len],chengshu[6]; //最终结果,临时结果,底数乘数 while(cin>>r>>n) { //初始化 for(int i=0;i<len;++i) jieguo[i]=result[i]=0; for(int i=0;i<6;++i) chengshu[i]=0; dianwei=0; //得到底数小数点位置 size_t pos = r.find('.'); //如果底数中有小数点 获取小数点后面有多少位数 if(pos!=string::npos) dianwei=(5-pos)*n; //把底数中所有不是小数点的数字挑出来转换为int并赋给最终结果,临时结果,底数乘数 得到的是3个5位前后颠倒的数组 之所以颠倒是因为乘法是从后往前乘的 for(int i=5,j=0;i>=0;--i) { if(r[i]!='.') { jieguo[j]=result[j]=chengshu[j]=r[i]-'0'; ++j; } } //当指数大于1时 进行以下运算 等于1时跳过这段程序直接输出 while(n>=2) { --n; //初始化最终结果数组 for(int i=0;i<len;++i) result[i]=0; for(int i=0;i<5;++i) //从底数乘数的每一位 { //底数乘数每位数和临时结果每位数相乘的临时变量 int temp; for(int j=0;j<len;++j) //乘以临时结果的每一位 { //如果底数乘数某一位是0 没必要乘下去了 跳出当前循环 if(chengshu[i]==0) break; temp=chengshu[i]*jieguo[j]; //i+j实现乘法相加时的移位 result[i+j]+=temp; //++t遍历所有结果数组中大于9的数 用除法和取模实现进位和余数 for(int t=i+j;result[t]>9;++t) { result[t+1]+=result[t]/10; result[t]=result[t]%10; } } } //把一次乘法后的结果赋给临时结果来进行下次乘方 for(int i=0;i<len;++i) jieguo[i]=result[i]; } //获取最终结果从后数第一个不为0的数作为第一个数的标志位 之所以从后数 是因为之前颠倒的数要颠倒回来了 int firstindex=-1; for(int i=len;i>=dianwei;--i) { if(result[i]>0) { firstindex=i; break; } } //获取 最终结果从前数第一个不为0的数作为最后一个数的标志位 int lastindex=-1; for(int i=0;i<dianwei;++i) { if(result[i]>0) { lastindex=i; break; } } //如果最终结果数组中不全是0 倒序输出结果数组中小数点前面的数 if(firstindex!=-1) { while(firstindex>=dianwei) { cout<<result[firstindex]; --firstindex; } } //如果最终结果数组中不全是0 倒序输出结果数组中小数点后面的数 if(lastindex!=-1) { cout<<'.'; --dianwei; while(dianwei>=lastindex) { cout<<result[dianwei]; --dianwei; } } cout<<endl; } } 

#附录:

一.高精度数的存储

1.字符串输入

#include <iostream>
#include <cstring> using namespace std; const int N=100;//最多100位 int main() { int a[N+1],i; string s1; cin>>s1;//数s1 memset(a,0,sizeof(a)); //数组清0 a[0]=s1.length(); //位数 for(i=1;i<=a[0];i++) { a[i]=s1[a[0]-i]-'0';//将字符转为数字并倒序存储. } return 0; }

2.直接读入

#include <iostream>
using namespace std; const int N=100;//最多100位 int main() { int a[N+1],i,s,key; cin>>key;//数key memset(a,0,sizeof(a)); //数组清0 i=0;//第0位 while(key) //当key大于0 { a[++i]=key%10;//取第i位的数 key=key/10; } a[0]=i; //共i位数 return 0; }

3.直接初始化(用a[]存储)

  • 初始化为0: memset(a,0,sizeof(a));
  • 初始化为1: memset(a,0,sizeof(a));a[0]=1;a[1]=1;

以下程序都只写函数,不写完整程序,所有高精度数存储都满足上述约定。

二.高精度数比较

int compare(int a[],int b[]) //比较a和b的大小关系,若a>b则为1,a<b则为-1,a=b则为0 { int i; if (a[0]>b[0]) return 1;//a的位数大于b则a比b大 if (a[0]<b[0]) return -1;//a的位数小于b则a比b小 for(i=a[0];i>0;i--) //从高位到低位比较 { if (a[i]>b[i]) return 1; if (a[i]<b[i]) return -1; } return 0;//各位都相等则两数相等。 }

三、高精度加法

int plus(int a[],int b[]) //计算a=a+b
{int i,k; k=a[0]>b[0]?a[0]:b[0]; //k是a和b中位数最大的一个的位数 for(i=1;i<=k;i++) { a[i+1]+=(a[i]+b[i])/10; //若有进位,则先进位 a[i]=(a[i]+b[i])%10; //计算当前位数字,注意:这条语句与上一条不能交换。 } if(a[k+1]>0) { a[0]=k+1; //修正新的a的位数(a+b最多只能的一个进位) } else { a[0]=k; } return 0; }

四、高精度减法

int gminus(int a[],int b[]);//计算a=a-b,返加符号位0:正数 1:负数 { int flag,i flag=compare(a,b); //调用比较函数判断大小 if (falg==0)//相等 { memset(a,0,sizeof(a));return 0; //若a=b,则a=0,也可在return前加一句a[0]=1,表示是 1位数0 } if(flag==1) //大于 { for(i=1;i<=a[0];i++) { if(a[i]<b[i]){ a[i+1]--;a[i]+=10;} //若不够减则向上借一位 a[i]=a[i]-b[i]; } while(a[a[0]]==0) a[0]--; //修正a的位数 return 0; } if (flag==-1)//小于 则用a=b-a,返回-1 { for(i=1;i<=b[0];i++) { if(b[i]<a[i]){ b[i+1]--;b[i]+=10; //若不够减则向上借一位 } a[i]=b[i]-a[i];} a[0]=b[0]; while(a[a[0]]==0) a[0]--; //修正a的位数 return -1; } }

五、高精度乘法(高精度乘单精度数,单精度数是指通常的整型数)

int multi1(int a[],long key) //a=a*key,key是单精度数 { int i,k; if (key==0){memset(a,0,sizeof(a));a[0]=1;return 0;} //单独处理key=0 for(i=1;i<=a[0];i++) { a[i]=a[i]*key;//先每位乘起来 } for(i=1;i<=a[0];i++) { a[i+1]+=a[i]/10;a[i]%=10; //进位 } //注意上一语句退出时i=a[0]+1 while(a[i]>0) { a[i+1]=a[i]/10;a[i]=a[i]%10;i++;a[0]++]; //继续处理超过原a[0]位数的进位,修正a的位数 } return 0; }
 
分类:  ACM

转载于:https://www.cnblogs.com/qiannong/p/10052470.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值