• 1001. Exponentiation高精度运算总结


    • 解题思路

    这道题属于高精度乘法运算,要求输入一个实数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;
    }
    
  • 相关阅读:
    ASP.NET MVC 入门9、Action Filter 与 内置的Filter实现(介绍) 【转】
    一个建议,看看大家的意见。
    发现不错的文章,推!
    有个小问题,大家一起研究。
    逼不得已,这个我确实不会,昨办?
    MSN Message6.2 的小BUG
    在IE7浏览器中切换成以资源管理器方式
    手机罗盘(指南针)校准方法
    G13/ Wildfire S/A510e link2SD教程,干净清洁的安装程序到内存卡
    HTC G13电池怎么鉴别真伪
  • 原文地址:https://www.cnblogs.com/qiaogaojian/p/6719842.html
Copyright © 2020-2023  润新知