标题:北大 POJ 关于高精度幂的问题
只看楼主
巧若拙
Rank: 4
来 自:宁波余姚
等 级:业余侠客
威 望:1
帖 子:159
专家分:273
注 册:2014-8-24
结帖率:46.15%
已结贴  问题点数:20 回复次数:5 
北大 POJ 关于高精度幂的问题
我的程序能够正确输出结果,可是测试反馈“Output Limit Exceeded”。到底哪里出了问题?请大牛指点!


/*
    Name: 求高精度幂
    Copyright:
    Author: 巧若拙
    Date: 31/10/14 12:42
    Description: 求高精度幂
Time Limit: 500MS        Memory Limit: 10000K
Total Submissions: 137841        Accepted: 33704
Description

对数值很大、精度很高的数进行高精度计算是一类十分常见的问题。比如,对国债进行计算就是属于这类问题。

现在要你解决的问题是:对一个实数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 。如果输出是整数,不要输出小数点。
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
Source

East Central North America 1988
Translator

北京大学程序设计实习,Xie Di

*/
#include<stdio.h>
#include<stdlib.h>

#define MAX 2000

typedef struct Node{
    int val[MAX];//存储数字
    int len, fra;//分别表示数字个数和小数部分长度
} Node;

Node CreatNode(char str[]);
Node Pow(Node A, int n);
Node Mul(Node A, Node B);
void PrintNode(Node A);

int main(void)
{
       char str[MAX];
       Node A, B;
       int n;
      
       while (scanf("%s%d", str, &n) != 0)
       {
          //    printf("s= %s, n = %d\n", str, n);
           A = CreatNode(str);
           B = Pow(A, n);
           PrintNode(B);
       }

    return 0;
}

Node CreatNode(char str[])
{
    int i, n, f;
    Node A;
   
    i = n = f = 0;
    while (str[i] != '.' && str[i] != '\0')//获取整数部分
    {
        A.val[n++] = str[i++] - '0';
    }
   
    if (str[i] == '.')
    {
        i++;
        while (str[i] != '\0')//获取小数部分
        {
            f++;
            A.val[n++] = str[i++] - '0';
        }
    }
    A.len = n;
    A.fra = f;
   
    if (A.fra > 0)//消除小数部分多余的后缀0
    {
        while (A.val[A.len-1] == 0)
        {
            A.fra--;
            A.len--;
        }   
    }
   
    return A;
}

Node Pow(Node A, int n)
{
    Node B, C;
   
    if (n == 1)
        return A;
    if (n == 0)
    {
        C.val[0] = C.len = 1;
        C.fra = 0;
        return C;
    }
   
    B = Pow(A, n/2);
    C = Mul(B, B);
   
    if (n % 2 == 1)
        C = Mul(C, A);
   
    return C;
}

Node Mul(Node A, Node B)
{
    Node C;
    int M[MAX] = {0};
    int i, j, k, d, s;
   
    for (d=1,i=A.len-1; i>=0; i--)
    {
        k = MAX - d;
        d++;
        for (j=B.len-1; j>=0; j--)
        {
            s = A.val[i] * B.val[j] + M[k]; //直接在M[k]中取进位
            M[k] = s % 10;
            M[--k] += s / 10; //把进位存储到M[k-1]
        }
        while (M[k] >= 10) //分解多位数
        {
            s = M[k];
            M[k] = s % 10;
            M[--k] = s / 10;
        }
    }
   
    while (M[k] == 0)//去除多余的前缀0
        k++;
        
    for (i=0; k<MAX; i++)//复制数字到C
        C.val[i] = M[k++];
   
    C.len = i;
    C.fra = A.fra + B.fra;
   
    if (C.fra > 0)//消除小数部分多余的后缀0
    {
        while (C.val[C.len-1] == 0)
        {
            C.fra--;
            C.len--;
        }   
    }
   
    return C;
}

void PrintNode(Node A)
{
    int z = A.len - A.fra;
    int i;
   
    for (i=0; i<z; i++)
        printf("%d", A.val[i]);
   
    if (z < A.len)
    {
        printf(".");
        for ( ; i<A.len; i++)
            printf("%d", A.val[i]);
    }
    printf("\n");
}
搜索更多相关主题的帖子: Copyright Memory 
2014-10-31 15:49
rjsp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:507
帖 子:8890
专家分:53117
注 册:2011-1-18
得分:10 
对一个实数R( 0.0 < R < 99.999 )
--- 没看懂,那输入是不是可以为 0.1234567890123456789012345678901234567890123456789012345678901234567890 ?
总得有个限定吧,我原以为限定为小数点后3位,但看你的Sample Input,又不是这样
2014-10-31 16:34
beyondyf
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:103
帖 子:3282
专家分:12654
注 册:2008-1-21
得分:10 
首先,main函数里 while (scanf("%s%d", str, &n) != 0) 这句是错的,循环不能正确结束。应该用 “==2”或者“!=EOF”或者“!=-1”

第二,你测试过样例里的第二组数据了么?你的前导零删除有问题。mul函数中while(M[k] == 0)这个逻辑有问题。当乘数小于1时,它会将本属于小数点后的零也删掉。

可以改成这样,while (MAX - k > A.fra + B.fra && M[k] == 0)

重剑无锋,大巧不工
2014-10-31 18:09
巧若拙
Rank: 4
来 自:宁波余姚
等 级:业余侠客
威 望:1
帖 子:159
专家分:273
注 册:2014-8-24
得分:0 
谢谢!
2014-10-31 18:53
巧若拙
Rank: 4
来 自:宁波余姚
等 级:业余侠客
威 望:1
帖 子:159
专家分:273
注 册:2014-8-24
得分:0 
非常感谢beyondyf,帮我指出了2个问题,其实还有1个问题,就是“消除小数部分多余的后缀0 ”。现在终于通过了!啊哈,这是我在北大POJ递交的第一个程序,值得纪念。
Run ID       User          Problem    Result    Memory    Time    Language    Code Length    Submit Time
13585688    QiaoRuoZhuo    1001    Accepted    504K    0MS    GCC    3722B    2014-10-31 20:23:00

/*
    Name: 求高精度幂
    Copyright:
    Author: 巧若拙
    Date: 31/10/14 12:42
    Description: 求高精度幂
Time Limit: 500MS        Memory Limit: 10000K
Total Submissions: 137841        Accepted: 33704
Description

对数值很大、精度很高的数进行高精度计算是一类十分常见的问题。比如,对国债进行计算就是属于这类问题。

现在要你解决的问题是:对一个实数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 。如果输出是整数,不要输出小数点。
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
Source

East Central North America 1988
Translator

北京大学程序设计实习,Xie Di

*/
#include<stdio.h>
#include<stdlib.h>

#define MAX 2000

typedef struct Node{
    int val[MAX];//存储数字
    int len, fra;//分别表示数字个数和小数部分长度
} Node;

Node CreatNode(char str[]);
Node Pow(Node A, int n);
Node Mul(Node A, Node B);
void PrintNode(Node A);

int main(void)
{
    char str[MAX];
    Node A, B;
    int n;
      
    while (scanf("%s%d", str, &n) == 2)
    {
//        printf("s= %s, n = %d\n", str, n);
        A = CreatNode(str);
        B = Pow(A, n);
          PrintNode(B);
    }

    return 0;
}

Node CreatNode(char str[])
{
    int i, n, f;
    Node A;
   
    i = n = f = 0;
    while (str[i] != '.' && str[i] != '\0')//获取整数部分
    {
        A.val[n++] = str[i++] - '0';
    }
   
    if (str[i] == '.')
    {
        i++;
        while (str[i] != '\0')//获取小数部分
        {
            f++;
            A.val[n++] = str[i++] - '0';
        }
    }
    A.len = n;
    A.fra = f;
   
    while (A.fra > 0 && A.val[A.len-1] == 0)//消除小数部分多余的后缀0
    {
        A.fra--;
        A.len--;   
    }
   
    return A;
}

Node Pow(Node A, int n)
{
    Node B, C;
   
    if (n == 1)
        return A;
    if (n == 0)
    {
        C.val[0] = C.len = 1;
        C.fra = 0;
        return C;
    }
   
    B = Pow(A, n/2);
    C = Mul(B, B);
   
    if (n % 2 == 1)
        C = Mul(C, A);
   
    return C;
}

Node Mul(Node A, Node B)
{
    Node C;
    int M[MAX] = {0};
    int i, j, k, d, s;
   
    for (d=1,i=A.len-1; i>=0; i--, d++)
    {
        if (A.val[i] == 0)//乘数是0就直接跳过
            continue;
        
        k = MAX - d;   
        for (j=B.len-1; j>=0; j--)
        {
            s = A.val[i] * B.val[j] + M[k]; //直接在M[k]中取进位
            M[k] = s % 10;
            M[--k] += s / 10; //把进位存储到M[k-1]
        }
        while (M[k] >= 10) //分解多位数
        {
            s = M[k];
            M[k] = s % 10;
            M[--k] = s / 10;
        }
    }
   
    while (MAX-k < A.fra + B.fra) //若整数部分为0,补足小数部分的前缀0
    {
        M[--k] = 0;
    }
    while (MAX-k > A.fra + B.fra && M[k] == 0)//去除多余的前缀0
        k++;
        
    for (i=0; k<MAX; i++)//复制数字到C
        C.val[i] = M[k++];
   
    C.len = i;
    C.fra = A.fra + B.fra;
   
    while (C.fra > 0 && C.val[C.len-1] == 0)//消除小数部分多余的后缀0
    {
           C.fra--;
        C.len--;   
    }
   
    return C;
}

void PrintNode(Node A)
{
    int z = A.len - A.fra;
    int i;
   
    for (i=0; i<z; i++)
        printf("%d", A.val[i]);
   
    if (z < A.len)
    {
        printf(".");
        for ( ; i<A.len; i++)
            printf("%d", A.val[i]);
    }
    printf("\n");
}
2014-10-31 20:31
beyondyf
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:103
帖 子:3282
专家分:12654
注 册:2008-1-21
得分:0 
不客气。

再提点改进的建议,你的数据是以结构体存储的,参数传递也是用的结构体,这个过程中涉及大量的数组拷贝。建议改用指针。

或者就是偏爱传值,那也可以缩小数组的尺寸。从题目描述看,数据的有效数字最多是5个,幂次最大是25,所以有效位数不超过125个。喜欢对齐的话那么开128的数组就够了。

重剑无锋,大巧不工
2014-10-31 21:15



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-437947-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.100543 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved