Uva 748 Exponentiation(大数相乘)

Exponentiation 

Time limit: 3.000 seconds

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 \le 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 Rn. Leading zeros and insignificant trailing zeros should be suppressed in the 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

Miguel A. Revilla 
2000-02-09
 
测试数据:
 
input:
 

0.0110 1
1000. 2
1000 4
10 1
10.0 1
10. 1

output:

.011
1000000
1000000000000
10
10
1

#include<stdio.h>
#include<string.h>
#include<time.h>
#define MAXN 1000
int temp[MAXN];
int temple[MAXN];
int patience[MAXN];
int sum[MAXN], large = 0;
char last[MAXN];

int add(int len, int level)
{// 一次相乘时累加各各位数上相乘得到的数 
    int i, j, e, item;
    for(i=0,e=0; i<len; ++i)
    {
        item = (e + temple[i] + sum[i+level]);
        sum[i+level] = item%10;
        e = item/10;
    }
    for(; e!=0; ++i)
    {
        item = e + sum[level+i];
        sum[i+level] = item%10;
        e = item/10;
    }
    if(i+level > large) large = i+level;
    
}

int multi(int n, int len)
{// 进入这个函数时先将patience的值赋予底的值 
    int i, j, e, cnt, strlen, item, t, m, t_n = n-1; // t_n的值为指数减1,统计需要相乘的次数 
    memset(sum, 0, sizeof(sum));
    memset(temple, 0, sizeof(temple));
    large = len;
    while(t_n--)
    {
        strlen = large;
        for(i=0; i<len; ++i)  
        {// 一次for循环完成时,两个大数相乘的目的达到 
            item = temp[i];
            for(j=0, e=0; j<strlen; ++j)
            {
                m = item*patience[j];
                temple[j] = (e + m)%10;
                e = (e + m)/10;
            }
            cnt = strlen;
            if(e) temple[j] = e, cnt++;
            add(cnt, i);
            memset(temple, 0, sizeof(temple)); 
        }
        
        memset(patience, 0, sizeof(patience));
        for(i=0; i<large; ++i) patience[i] = sum[i];
        memset(sum, 0, sizeof(sum));   // 每次将相乘得到的结果赋值给patience时将sum归零
    }    
    
    return 0;
}

int main()
{
    clock_t begin, end;
    int i, j, k, cnt, t, len, m, high, low;
    char input[10], *str;
    int n;
    begin = clock();
     while(scanf("%s%d", input, &k) != EOF)
     {
         len = strlen(input);
         m = -1;
         if((str = strchr(input, '.')) != NULL)
         m = len - 1 - (str - input);   // m 的作用是计算小数点后面有几位小数,无小数点时m=-1 
        memset(temp, 0, sizeof(temp));
        memset(patience, 0, sizeof(patience));
        for(i=len-1,n=0; i>=0; --i)
         if(input[i] != '.') temp[n++] = patience[n] = input[i] - '0';
         
         if(m != -1) len--; 
        if(k>=2) multi(k, len);    
        else if(k == 1)  // 处理指数为1的情况 
        {
            high = len-1, low = 0;  
            // high 和 low 两个变量主要是消除前缀零和尾数零的情况, 同时,若存在小数点 
            // 而且是有必要消除时,比如说1000. 用这两个变量根据情况判断也可以消去 
            for(i=0; input[i] == '0'; ++i); low = i;
            if(m != -1)
            {
                for(i=len-1; input[i] == '0'; --i); high = i;
                if(input[high] == '.') high--;
            } 
            
            for(i=low; i<=high; ++i) printf("%c", input[i]);
            printf("\n");
            continue;
        }
        
        
        
        if(m == -1) // 处理无小数点的情况,而这时的尾数零不用消去 
        {
            low = 0, high = large - 1;
            for(i=large-1; patience[i] == 0; --i); high = i;
            for(i=high; i>=low; --i) printf("%d", patience[i]);
            printf("\n");
        }
        else
        {// 当存在小数点时,必须先将小数点放入大数内才能开始消去前缀零和尾数零 
            cnt = 0;
            t = m*k;  // 计算最后一共有几个小数,没有先处理尾数零的其中原因之一就是避免不能准确计算t 
            memset(last, 0, sizeof(last)); // 建立一个字符串数组,作用是存储加入小数点后的大数 
            for(i=0; i<t; ++i)
            {
                sprintf(last+cnt, "%d", patience[i]);  // sprintf函数将整型转换成了字符放入了字符串中 
                cnt++;
            }
            last[cnt++] = '.';   // 放入小数点 
            for(; i<large; ++i)
            {
                sprintf(last+cnt, "%d", patience[i]); 
                cnt++;
            }
            last[cnt] = '\0';
            len = strlen(last);
            low = 0, high = len-1;
            for(i=len-1; last[i] == '0'; i--); high = i;  // 同样的形式处理前缀零和尾数零 
            for(i=0; last[i] == '0'; i++); low = i;
            if(last[low] == '.') low++; 
            for(i=high; i>=low; i--) printf("%c", last[i]);
            printf("\n");
        }
        
     }
    end = clock();
    printf("time = %dms\n", end - begin);
    return 0;
}

解题思路:

先将浮点数转换成整型,同时统计小数点后面数得个数,再进行大数相乘   1y

原文地址:https://www.cnblogs.com/liaoguifa/p/2832936.html