《编程思维与实践》1060.浮点数加法
题目
思路
浮点数可以分为[整数部分].[小数部分],可以将两个部分分开处理,最后再合并,但在处理四舍五入时较为繁琐,
为了方便起见,这里采用将两个部分一起处理的方式:
由于浮点数不超过500位:整数部分最多500位,小数部分最多500位,所以加法后的结果整数部分最多501位,小数部分最多500位.
所以可以宏定义L=500,数组最大长度为2L+1,其中[0,L]存整数部分,[L+1,2L+1]存小数部分;
具体步骤:
用结构体存浮点数,cnt存整数部分位数.
1.读取浮点数:
①有小数点:找到小数点的位置,小数点前逆向遍历存取整数部分,小数点后正向遍历存取小数部分;
②无小数点(遍历到字符串末尾):从字符串末尾逆向遍历存整数部分.
2.浮点数加法:
先将保留位(N位)后的部分相加,进位后判断保留位的后一位是四舍还是五入;
再将保留位和前面的部分相加,最后进行进位.
3.输出浮点数,整数部分根据位数输出,补一个小数点后再输出小数部分到保留位即可.
注意的点:
1.(坑)测试数据中,两个大整数可能含有前置0,所以在读取时计算整数位数需要去除前置0;
2.加法在进位时需要判断是否要多一位.
代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define L 500
typedef struct{int cnt,v[2*L+1];}FLOAT; //cnt这里存的是整数位数
FLOAT carry(FLOAT S,int bin); //进位 bin表示进制 binary
FLOAT Input(); //input a float number
FLOAT add(FLOAT S,FLOAT T,int N); //顺序加
void output(FLOAT A,int N); //输出
int main()
{
FLOAT A=Input();
FLOAT B=Input();
int N;
scanf("%d",&N);
FLOAT ans=add(A,B,N);
output(ans,N);
return 0;
}
FLOAT carry(FLOAT S,int bin) //进位 bin表示进制 binary
{
int flag=0;
for(int i=2*L;i>=L-S.cnt+1;i--) //顺序存 进位需要逆着进行
{
int temp=S.v[i]+flag;
S.v[i]=temp%bin;
flag=temp/bin;
}
if(flag) //判断是否要进一位
{
S.cnt++;
S.v[L-S.cnt+1]=flag;
}
return S;
}
FLOAT Input() //input a float number
{
char s[L+1];
scanf("%s",s);
FLOAT A={0,{0}};
int i=0;
while(i<strlen(s)&&s[i]!='.') //无小数点和有小数点的情况都包含
{
i++; //定位小数点
}
if(i==0)
{
A.cnt++; //整数部分为0
}
for(int j=i-1,k=L;j>=0;j--)
{
A.cnt++;
A.v[k--]=s[j]-'0'; //整数部分
}
for(int j=i+1,k=L+1;j<strlen(s);j++)
{
A.v[k++]=s[j]-'0'; //小数部分
}
for(int i=L-A.cnt+1;i<L&&A.v[i]==0;i++) //去除读入内容的前置0
{
A.cnt--;
}
return A;
}
FLOAT add(FLOAT S,FLOAT T,int N) //顺序加
{
int max=S.cnt>T.cnt?S.cnt:T.cnt;
FLOAT R={max,{0}};
int i;
for(i=2*L;i>=0;i--)
{
R.v[i]=S.v[i]+T.v[i];
}
R=carry(R,10);
if(R.v[L+N+1]>=5) //保留位的下一位
{
R.v[L+N]++; //四舍五入
}
R=carry(R,10);
return R;
}
void output(FLOAT A,int N)
{
for(int i=L-A.cnt+1;i<=L+N;i++)
{
if(i==L+1)
{
printf(".");
}
printf("%d",A.v[i]);
}
}