C语言PAT刷题 - 1024 科学计数法

作者的话:若有朋友复制代码去PAT试着运行遇到问题的:
1.可能是格式问题,可以先把从本站复制的代码粘贴到记事本,再把记事本里的代码复制,然后粘贴到PAT的代码区,提交本题回答,应该就可以了;
2.可能是注释原因,PAT有时候检测到注释会编译错误,所以可以先把注释删了,再进行提交回答;
3.可能是作者当初根据题目写出来的代码仍存在一些疏漏,而恰好当时的测试机制没那么完善,没检测出问题。后面测试机制有所更新,故出现问题,若有相关需要的可以评论区留言或私信作者,我看到的话会去再查一下疏漏之处,然后更新文章。

一、题目描述
科学计数法是科学家用来表示很大或很小的数字的一种方便的方法,其满足正则表达式 [±][1-9].[0-9]+E[±][0-9]+,即数字的整数部分只有 1 位,小数部分至少有 1 位,该数字及其指数部分的正负号即使对正数也必定明确给出。

现以科学计数法的格式给出实数 A,请编写程序按普通数字表示法输出 A,并保证所有有效位都被保留。

输入格式:
每个输入包含 1 个测试用例,即一个以科学计数法表示的实数 A。该数字的存储长度不超过9999 字节,且其指数的绝对值不超过9999。

输出格式:
对每个测试用例,在一行中按普通数字表示法输出 A,并保证所有有效位都被保留,包括末尾的0。

输入样例 1:
+1.23400E-03
输出样例 1:
0.00123400
输入样例 2:
-1.2E+10
输出样例 2:
-12000000000
二、解题思路
读题:

1.接收科学记数法格式的实数A,输出普通数字法表示的实数A;
2.因为要求所有有效位都被保留,包括末尾的0,采用浮点型变量存储有有效位位数限制,所以只能采用字符数组来存储实数A;
3.因为题目限制该数字的存储长度不超过9999 字节,且其指数的绝对值不超过9999,所以对于科学记数法格式的±AE±X(A为浮点数,X为指数),最坏的情况是两个正负号总共占2个字节,E占1个字节,X=9999,占四个字节,前面这些总共占7个字节,A可占9992个字节,即可以放9991个数字和一个小数点。最后的结果最坏是-0.0……(A前面最多可以有9999个连续的0,包括小数点前面的0;此时A是去除小数点后的一串数字)A,其中-和小数点占2个字节,A前面的0占9999个字节,A占9991个字节(因为小数点在前面算过了,这里的A只包含数字),总共19992个字节,为了后面方便输出,一般会以字符串格式输出数组a的内容,所以还要多开拓一个字节的空间存储’\0’,总共19993的字节,所以为了方便,也为了防止少算某些空间,给字符数组a设置20000个元素。

思路:
1.设置需要的变量,设置循环接收科学记数法格式的实数A存储在字符数组a中,当接收到’E’时,把此时的i的值赋值给n,即之后a[n]=E;
2.首先对第一个正负号进行判断,这个正负号决定了实数A的正负性,根据题目给出的输入输出样例,可知当实数A为正时,不输出’+‘;当实数A为负时,输出’-‘。设置判断语句,处理好正负性的表现形式;
3.设置循环,计算出指数的值(即数组a下标从n+2开始,一直到存储换行符的a[i]之前,这一连串数字组成的数);
4.设置判断语句,根据指数的正负性进入相应的分支:
(1)当指数为正且指数数字部分sum < (n - 3)(小数点后的数字总共是n-3个)时,此时小数点后移sum位,由于小数点后依然有小数,所以小数点保留;
(2)当指数为正且sum>=(n - 3)(小数点后的数字总共是n-3个)时,小数点后移到原小数点后的所有数字后面,此时小数点后已经没有小数,小数点不再需要。若sum-(n-3)后>0,则根据差在所有数字后面补上0;
(3)当指数为负时,若指数的数字部分sum为0,将科学记数法格式下实数A的数字部分不作改变,直接进行输出;若不为0,小数点后的数字分别向后移动sum位,小数点前的整数部分后移sum+1位(因为他要多跨越一个’.'),小数点不变,移动后的数字前面是0.0……的形式。
三、具体实现
0.标准C源程序框架

#include <stdio.h>
int main()
{
    return 0;
}

1.设置需要的变量,设置循环接收科学记数法格式的实数A存储在字符数组a中,当接收到’E’时,把此时的i的值赋值给n,即之后a[n]=E;

    char a[20000];//该数字的存储长度不超过 9999 字节,且其指数的绝对值不超过 9999
    int i = 0;
    int n = 0;
    int sum = 0;
    do {
        a[i]=getchar();
        if(a[i]=='E')     n = i;//a[n]='E'
    } while (a[i++]!='\n');

2.首先对第一个正负号进行判断,这个正负号决定了实数A的正负性,根据题目给出的输入输出样例,可知当实数A为正时,不输出’+‘;当实数A为负时,输出’-'。设置判断语句,处理好正负性的表现形式;

    if (a[0] == '+');//为正时啥也不用干
    else     printf("-");//为负时输出'-'

3.设置循环,计算出指数的数字部分的值(即数组a下标从n+2开始,一直到存储换行符的a[i]之前,这一连串数字组成的数);

    for (i=n+2;a[i]!='\n';i++)
    {
        sum = sum * 10 + a[i]-'0';//指数的值
    }

4.设置判断语句,根据指数的正负性进入相应的分支:
(1)当指数为正且指数数字部分sum < (n - 3)(小数点后的数字总共是n-3个)时,此时小数点后移sum位,由于小数点后依然有小数,所以小数点保留;

    if (a[n + 1] == '+')
        if (sum < (n - 3))
        {
            for (i = 3; i < (3 + sum); i++)
            {
                a[i - 1] = a[i];
            }
            a[sum + 2] = '.';
            a[n] = '\0';
            printf("%s",&a[1]);
        }

(2)当指数为正且sum>=(n - 3)(小数点后的数字总共是n-3个)时,小数点后移到原小数点后的所有数字后面,此时小数点后已经没有小数,小数点不再需要。若sum-(n-3)后>0,则根据差在所有数字后面补上0;

        else
        {
            printf("%c",a[1]);
            a[n] = '\0';
            printf("%s", &a[3]);
            sum -= n - 3;
            while (sum--)   printf("0");
        }

(3)当指数为负时,若指数的数字部分sum为0,将科学记数法格式下实数A的数字部分不作改变,直接进行输出;若不为0,小数点后的数字分别向后移动sum位,小数点前的整数部分后移sum+1位(因为他要多跨越一个’.'),小数点不变,移动后的数字前面是0.0……的形式。

 else
    {
        for (i=n-1;i>=1;i--)
        {
            if(sum!=0)
            {
                if (i == 2);
                else if (i == 1)
                {
                    a[i + sum + 1] = a[i];
                    a[1] = '0';
                }
                else
                {
                    a[i + sum] = a[i];
                    a[i] = '0';
                }
            }
        }
        for (i = n; i < 1 + sum + 1; i++)
            a[i] = '0';
        a[n + sum] = '\0';
        printf("%s", &a[1]);
    }

四、测试数据
输入样例 1:
+1.23400E-03
输出样例 1:
0.00123400

输入样例 2:
-1.2E+10
输出样例 2:
-12000000000

输入样例 3://当指数为0时你的程序能否返回正确的结果?
+1.23400E-0
输出样例 3:
1.23400

输入样例 4://当指数引入的0的个数大于原数字长度时你的程序能否返回正确的结果?
+1.23400E-100
输出样例 4:
0.00……123400(1234前面总共100个0,包括小数点前面的0)

五、全部代码

#include <stdio.h>  
int main() {
    char a[20000];//该数字的存储长度不超过 9999 字节,且其指数的绝对值不超过 9999
    int i = 0;
    int n = 0;
    int sum = 0;
    do {
        a[i]=getchar();
        if(a[i]=='E')     n = i;//a[n]='E'
    } while (a[i++]!='\n');
    if (a[0] == '+');//为正时啥也不用干
    else     printf("-");//为负时输出'-'
    for (i=n+2;a[i]!='\n';i++)
    {
        sum = sum * 10 + a[i]-'0';//指数的值
    }
    if (a[n + 1] == '+')
        if (sum < (n - 3))
        {
            for (i = 3; i < (3 + sum); i++)
            {
                a[i - 1] = a[i];
            }
            a[sum + 2] = '.';
            a[n] = '\0';
            printf("%s",&a[1]);
        }
        else
        {
            printf("%c",a[1]);
            a[n] = '\0';
            printf("%s", &a[3]);
            sum -= n - 3;
            while (sum--)   printf("0");
        }
    else
    {
        for (i=n-1;i>=1;i--)
        {
            if(sum!=0)
            {
                if (i == 2);
                else if (i == 1)
                {
                    a[i + sum + 1] = a[i];
                    a[1] = '0';
                }
                else
                {
                    a[i + sum] = a[i];
                    a[i] = '0';
                }
            }
        }
        for (i = n; i < 1 + sum + 1; i++)
            a[i] = '0';
        a[n + sum] = '\0';
        printf("%s", &a[1]);
    }
    return 0;
}
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值