C语言/C++常见习题问答集锦(三十六)之两个浮点数相加的遐想
程序之美
题目描述
求2个浮点数相加的和
题目中输入输出中出现浮点数都有如下的形式:
P1P2…Pi.Q1Q2…Qj
对于整数部分,P1P2…Pi是一个非负整数
对于小数部分,Qj不等于0
关于输入
第1行是测试数据的组数n,每组测试数据占2行,分别是两个加数。每组测试数据之间有一个空行,每行数据不超过100个字符
关于输出
n行,每组测试数据有一行输出是相应的和。输出保证一定是一个小数部分不为0的浮点数
例子输入
2
0.111111111111111111111111111111
0.111111111111111111111111111111
10000000.655555555555555555555555555555
1.444444444444444444444444444445
例子输出
0.222222222222222222222222222222
10000002.1
程序设计思想:
大体构思:这道题和我之前那道a+b(大数加法)类似,可以把整数部分和小数部分分开求解。
具体步骤:把整数部分和小数部分对齐,对齐就是使两浮点数字符串一样长,且小数点在相同的位置。
1、从结尾开始每位相加
2、遇到‘.’,就加入“.”到结果字符串中
3、最高位有进位,要再进一位
4、输出结果字符串
拿到这个题目,我在网上搜了个遍,看有没有哪个大神留下点思路,但是发现基本上都是C++版本的,很少有C语言版本的,于是就亲自操刀,实现如下:
解法一:
#include<stdio.h>
#include<string.h>
typedef struct _Ans
{
int ans1[150];
int count1;
int p10;
int ans2[150];
int count2;
int p20;
}Ans;
int main(){
int n;
int i,j,k,t = 0, m = 0, l = 0;
int alen,blen;
char a[150],b[150];
int a1[150]={0},b1[150]={0},a2[150]={0},b2[150]={0},ans1[150]={0},ans2[150]={0};
scanf("%d",&n);
if(n <= 0){
return 0;
}
l = n;
m = 0;
Ans *ans = (Ans *)malloc(sizeof(Ans) * n);
while(n--){
scanf("%s",&a);
scanf("%s",&b);
alen=strlen(a);
blen=strlen(b);
for(i=0;i<150;i++){
a1[i]=0;
a2[i]=0;
b1[i]=0;
b2[i]=0;
ans1[i]=0;
ans2[i]=0;
ans[m].ans1[i]=0;
ans[m].ans2[i]=0;
}
ans[m].count1 = 0;
ans[m].count2 = 0;
ans[m].p10 = 0;
ans[m].p20 = 0;
for(i=0;i<alen;i++){
if(a[i]=='.'){
k=0;
for(j=i-1;j>=0;j--){
a1[k++]=a[j]-'0';
}
k=0;
for(j=i+1;j<alen;j++){
a2[++k]=a[j]-'0';
}
}
}
for(i=0;i<blen;i++){
if(b[i]=='.'){
k=0;
for(j=i-1;j>=0;j--){
b1[k++]=b[j]-'0';
}
k=0;
for(j=i+1;j<blen;j++){
b2[++k]=b[j]-'0';
}
}
}
for(i=140;i>0;i--){
ans1[i]+=a2[i]+b2[i];
if(ans1[i]>=10){
ans1[i-1]+=1;
ans1[i]-=10;;
}
}
if (ans1[0]!=0) a1[0]=a1[0]+1;
for(i=0;i<=140;i++){
ans2[i]+=a1[i]+b1[i];
if(ans2[i]>=10){
ans2[i]%=10;
ans2[i+1]+=1;
}
}
for(i=140;i>=0;i--){
if(ans2[i]!=0){
for(j=i;j>=0;j--){
ans[m].ans2[ans[m].count2++] = ans2[j];
}
break;
}
}
if(i==-1) {
ans[m].p20 = 1;
}
for(i=140;i>0;i--){
if(ans1[i]!=0){
for(j=1;j<=i;j++){
ans[m].ans1[ans[m].count1++] = ans1[j];
}
break;
}
}
if(i==0)
{
ans[m].p10 = 1;
}
m ++;
printf("\n");
}
printf("\n");
for (i = 0; i < l; i++)
{
for (j = 0; j < ans[i].count2; j++)
{
printf("%d",ans[i].ans2[j]);
}
if(ans[i].p20==1)
{
printf("0");
}
printf(".");
for (j = 0; j < ans[i].count1; j++)
{
printf("%d",ans[i].ans1[j]);
}
if(ans[i].p10==1)
{
printf("0");
}
printf("\n");
}
free(ans);
return 0;
}
运行结果如下:
后来发现网上一位朋友有另外的解法如下:
#include<stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
int numberArr = 0;
scanf_s("%d", &numberArr);
char resArr[50][100];
for (int i = 0; i < numberArr; i++) {
char firstStr[100];
memset(firstStr, 0, 100);
char secendStr[100];
memset(secendStr, 0, 100);
char resStr[100];
memset(resStr, 0, 100);
char* buf;
scanf_s("%s", firstStr, 100);
scanf_s("%s", secendStr, 100);
char* str1f = strtok_s(firstStr, " ." ,&buf); //第一个数的整数部分
char* str1i = str1f;
if (str1f != NULL)
{
str1f = strtok_s(NULL, " .", &buf); //第一个数的小数部分
}
char* str2f = strtok_s(secendStr, " .", &buf); //第二个数的整数部分
char* str2i = str2f;
if (str2f != NULL)
{
str2f = strtok_s(NULL, " .", &buf); //第一个数的小数部分
}
int firstLen = strlen(str1f); //第一个数小数部分长度
int secendLen = strlen(str2f); //第二个数小数部分长度
int firstLenI = strlen(str1i); //第一个数小数部分长度
int secendLenI = strlen(str2i); //第二个数小数部分长度
if (firstLen > secendLen)
{
char resf[100];
char resi[100];
memset(resf, 0, 100);
memset(resi, 0, 100);
int carry = 0;
bool isLastE = true;
for (int j = (firstLen-1); j >= 0; j--)
{
if (j > (secendLen-1))
{
resf[j] = str1f[j];
}
else
{
//resf[j] = '0';
resf[j] = (char)(((int)str1f[j] + (int)str2f[j] + carry - 96) % 10) + 48;
carry = ((int)str1f[j] + (int)str2f[j] + carry - 96) / 10;
}
if (resf[j] != '0' && isLastE)
{
isLastE = false;
}
if (resf[j]=='0' && isLastE)
{
resf[j] = '\0';
}
}
int firstI = atoi(str1i);
int secendI = atoi(str2i);
sprintf_s(resi,"%d", (firstI + secendI+carry));
if (resf == NULL || resf[0] == '\0')
sprintf_s(resArr[i], 100, "%s", resi);
else
sprintf_s(resArr[i], 100, "%s.%s", resi, resf);
}
else
{
char resf[100];
char resi[100];
memset(resf, 0, 100);
memset(resi, 0, 100);
int carry = 0;
bool isLastE = true;
for (int j = (secendLen - 1); j >= 0; j--)
{
if (j > (firstLen - 1))
{
resf[j] = str1f[j];
}
else
{
//resf[j] = '0';
resf[j] = (char)(((int)str1f[j] + (int)str2f[j] + carry - 96) % 10) + 48;
carry = ((int)str1f[j] + (int)str2f[j] + carry - 96) / 10;
}
if (resf[j] != '0' && isLastE)
{
isLastE = false;
}
if (resf[j] == '0' && isLastE)
{
resf[j] = '\0';
}
}
int firstI = atoi(str1i);
int secendI = atoi(str2i);
sprintf_s(resi, "%d", (firstI + secendI + carry));
if (resf == NULL || resf[0] == '\0')
sprintf_s(resArr[i], 100, "%s", resi);
else
sprintf_s(resArr[i], 100, "%s.%s", resi, resf);
}
}
for (int i = 0; i < numberArr; i++)
{
printf("%s\n",resArr[i]);
}
return 0;
}
解法三:
#include<stdio.h>
#include<string.h>
int main(){
int n;
int i,j,k,t=0;
int alen,blen;
char a[150],b[150];
int a1[150]={0},b1[150]={0},a2[150]={0},b2[150]={0},ans1[150]={0},ans2[150]={0};
scanf("%d",&n);
while(n--){
scanf("%s",&a);
scanf("%s",&b);
alen=strlen(a);
blen=strlen(b);
for(i=0;i<150;i++){
a1[i]=0;
a2[i]=0;
b1[i]=0;
b2[i]=0;
ans1[i]=0;
ans2[i]=0;
}
for(i=0;i<alen;i++){
if(a[i]=='.'){
k=0;
for(j=i-1;j>=0;j--){
a1[k++]=a[j]-'0';
}
k=0;
for(j=i+1;j<alen;j++){
a2[++k]=a[j]-'0';
}
}
}
for(i=0;i<blen;i++){
if(b[i]=='.'){
k=0;
for(j=i-1;j>=0;j--){
b1[k++]=b[j]-'0';
}
k=0;
for(j=i+1;j<blen;j++){
b2[++k]=b[j]-'0';
}
}
}
for(i=140;i>0;i--){
ans1[i]+=a2[i]+b2[i];
if(ans1[i]>=10){
ans1[i-1]+=1;
ans1[i]-=10;;
}
}
if (ans1[0]!=0) a1[0]=a1[0]+1;
for(i=0;i<=140;i++){
ans2[i]+=a1[i]+b1[i];
if(ans2[i]>=10){
ans2[i]%=10;
ans2[i+1]+=1;
}
}
for(i=140;i>=0;i--){
if(ans2[i]!=0){
for(j=i;j>=0;j--){
printf("%d",ans2[j]);
}
break;
}
}
if(i==-1) printf("0");
printf(".");
for(i=140;i>0;i--){
if(ans1[i]!=0){
for(j=1;j<=i;j++){
printf("%d",ans1[j]);
}
break;
}
}
if(i==0) printf("0");
printf("\n");
}
}
运行结果如下:
关于C++的实现倒是有不少,如下:
解法一:
#include <bits/stdc++.h>
using namespace std;
struct bign{
int d[1001];
int s[1001];
int len;
int dlen;
int slen;
bign(){
memset(d, 0, sizeof(d));
memset(s, 0, sizeof(s));
len = 0;
dlen = 0;
slen = 0;
}
};
bign change(char str[]){
bign a;
a.len = strlen(str);
int i, j;
for(i=0; i<a.len; i++){
if(str[a.len - i - 1]!='.'){
a.slen++;
a.s[i] = str[a.len - i - 1] - '0';
}
else break;
}
int temp = a.len - i - 1;
for(j=0; j<temp; j++){
a.dlen++;
a.d[j] = str[temp - j - 1] - '0';
}
return a;
}
bign fadd(bign a, bign b){
bign c;
int i, j, k = 0, l = 0, carry = 0;
if(a.slen > b.slen){
for(k = 0; k<a.slen-b.slen; k++){
c.s[c.slen++] = a.s[k];
}
}
if(a.slen < b.slen){
for(l = 0; l<b.slen-a.slen; l++){
c.s[c.slen++] = b.s[l];
}
}
for(i=0; i+k<a.slen || i+l<b.slen; i++){
int temp = a.s[i+k] + b.s[i+l] + carry;
c.s[c.slen++] = temp % 10;
carry = temp / 10;
}
for(j=0; j<a.dlen || j<b.dlen; j++){
int temp = a.d[j] + b.d[j] + carry;
c.d[c.dlen++] = temp % 10;
carry = temp / 10;
}
if(carry!=0)
c.d[c.dlen++] = carry;
return c;
}
void out(bign a){
int k = 0;
if(a.s[k]==0){
while(a.s[k]==0)
k++;
}
for(int i=a.dlen - 1; i >=0; i--){
printf("%d", a.d[i]);
}
printf(".");
for(int i=a.slen - 1; i >=k; i--){
printf("%d", a.s[i]);
}
}
int main() {
int n;
scanf("%d", &n);
for(int i=0; i<n; i++){
char str1[1001], str2[1001];
scanf("%s%s", str1, str2);
bign a = change(str1);
bign b = change(str2);
bign c = fadd(a, b);
out(c);
printf("\n");
}
return 0;
}
解法二:
#include"stdio.h"
#include<iostream>
#include<string>
#include<algorithm>//为了用reverse函数
using namespace std;
typedef long long ll;
string a,b,c;
int main(){
//freopen("c://jin.txt","r",stdin);
while(cin>>a>>b){
int dota=a.find('.');//string的find函数,返回查找字符串的位置
int dotb=b.find('.');
int lena=a.length()-dota;
int lenb=b.length()-dotb;
int len=lena-lenb;
string tmp(abs(len),'0');//string的一种构造函数
if(len>0)b+=tmp;
else a+=tmp;
reverse(a.begin(),a.end());
reverse(b.begin(),b.end());
len=dota-dotb;
string tmp2(abs(len),'0');
if(len>0)b+=tmp2;
else a+=tmp2;
int k=0;
for(int i=0;i<a.length();i++)
{if(a[i]=='.')c+='.';//特别注意这里不能用c[i],否则会报错
else{ k=a[i]+b[i]-2*'0'+k;
c+=char(k%10+'0');
k=k/10;
}
}
if(k){
c+=char(k+'0');
}
while(c[0]=='0')c.erase(c.begin());
if(c[0]=='.')c.erase(c.begin());
reverse(c.begin(),c.end());
cout<<c<<endl;
}
//freopen("CON","r",stdin);
//system("pause");
return 0;
}
解法三:
#include <iostream>
using namespace std;
string addBigfloat(string sa, string sb)
{
string result, sc, sd;
//面是将两浮点数对齐
int ia = sa.find(".", 0); //寻找小数点位置
int ib = sb.find(".", 0);
sc = (ia>ib)?sa:sb; //整数部分长的
sd = (ia>ib)?sb:sa; //整数部分短的
int n = (ia>ib)?(ia-ib):(ib-ia); //整数部分长度的差值
while(n--)
{
sd = "0"+sd;
}
int lenc = sc.length();
int lend = sd.length();
sa = (lenc>lend)?sc:sd;
sb = (lenc>lend)?sd:sc;
n = (lenc>lend)?(lenc-lend):(lend-lenc); //小数部分长度的差值
while(n--)
{
sb+="0";
}
//下面是对对齐后的浮点数进行相加
int carry = 0;
for(int i = sa.length()-1; i>=0; i--)
{
if(sa[i]=='.') //遇到‘.’,就加入“.”到结果字符串中
{
result = "."+result;
continue;
}
char value = sa[i]-'0'+sb[i]-'0'+carry; //保存两数之和结果
result = char(value%10+'0')+result; //将结果加入到结果字符串中
carry = value/10; //计算进位
}
while(carry!=0) //若还有进位
{
result = char(carry%10+'0')+result;
carry/=10;
}
return result;
}
int main()
{
string sa, sb;
while(cin>>sa>>sb)
{
cout<<addBigfloat(sa, sb)<<endl;
}
return 0;
}
解法四:
#include<iostream>
#include<string.h>
#include<math.h>
using namespace std;
struct bigInt {
int d[1011];
int size;
int length = 0;//保存小数部分的位数
void init() {//初始化
for (int i = 0; i < 1011; i++) {
d[i] = 0;
}
size = 0;//目前还没有任何一个单位被使用
}
void set(char str[]) {//提取字符串
init();
int len = strlen(str);
for (int i = len - 1; i >= 0; i--) {
if (str[i]!='.') {
d[size++] = str[i] - '0';
}
else length = len - 1 - i;
}
//cout << length << endl;
}
void output() {//输出函数
int l = 0;
while (d[l] == 0) { l++; }
for (int i = size - 1; i >= l; i--) {
if (i == length - 1) printf(".");//输出小数点
printf("%d", d[i]);
}
if (size == 0) printf("0");
printf("\n");
}
};
bigInt add(bigInt a, bigInt b) {//十进制 大整数与大整数相加
bigInt res;
res.init();
res.length = a.length;//注意这一步!!!
int carry = 0;//进位,初始值为0
for (int i = 0; i < a.size || i < b.size; i++) {
int tmp = a.d[i] + b.d[i] + carry;
carry = tmp / 10;//计算进位
tmp %= 10;//该位的结果
res.d[res.size++] = tmp;//保存该位结果
}
while (carry > 0) {//结束计算后如果最高位有进位
res.d[res.size++] = carry % 10;
carry /= 10;
}
return res;
}
bigInt mul(bigInt a, int x) {//大整数乘普通整数
bigInt res;
res.init();
int carry = 0;
for (int i = 0; i < a.size; i++) {
int tmp = x*a.d[i] + carry;//carry不参与乘法运算
carry = tmp / 10;
tmp %= 10;
res.d[res.size++] = tmp;
}
while (carry > 0) {//注意最后对进位的处理
res.d[res.size++] = carry % 10;
carry /= 10;
}
return res;
}
int main() {
bigInt a, b;
char str1[1002], str2[1002];
while (cin >> str1 >> str2) {
a.set(str1);
b.set(str2);
int tmp = abs(a.length - b.length);
if (a.length > b.length) {//对齐小数部分 即对齐小数点
while (tmp--) { b = mul(b, 10); }//往短的小数部分后面补0
}
else if (a.length < b.length) {
while (tmp--) { a = mul(a, 10); }
a.length = b.length;//注意这里更新a.length
}
a = add(a, b);//大数相加
a.output();
}
return 0;
}
解法五:
#include<iostream>
#include<string>
using namespace std;
int main(){
string s1,s2;
while(cin>>s1){
cin>>s2;
int a[110]={0},b[110]={0};
int mida,midb,i;
int n1=s1.length(),n2=s2.length(),n;
for(i=0;i<n1;i++){
if(s1[n1-i-1]=='.'){
mida=i;
a[i]=-1;
}
else
a[i]=s1[n1-i-1]-'0';
}
for(i=0;i<n2;i++){
if(s2[n2-i-1]=='.'){
midb=i;
b[i]=-1;
}
else
b[i]=s2[n2-i-1]-'0';
}
if(mida<midb){
int len=midb-mida;
for(i=n1-1;i>=0;i--)
a[i+len]=a[i];
n1+=len;
for(i=0;i<len;i++)
a[i]=0;
}
else if(midb<mida){
int len=mida-midb;
for(i=n2-1;i>=0;i--)
b[i+len]=b[i];
n2+=len;
for(i=0;i<len;i++)
b[i]=0;
}
n=n1>n2?n1:n2;
int k=0;
for(i=0;i<n;i++){
if(a[i]==-1) continue;
int t=(a[i]+b[i]+k)/10;
a[i]=(a[i]+b[i]+k)%10;
k=t;
}
if(k!=0) a[n++]=k;
for(i=n-1;i>=0;i--){
if(a[i]==-1)
cout<<".";
else
cout<<a[i];
}
cout<<endl;
}
return 0;
}
解法六:
#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<string.h>//memset的头文件
using namespace std;
struct bign
{
int d[101];//数组要开的足够大,切记切记,这里错误了一次
int len ;//总长度
bign()
{
memset(d,0, sizeof(d));
len = 0;
}
};
int Find(char s[])//返回小数点的位数
{
for(int i=0; i<strlen(s); i++)
{
if(s[i]=='.')
return strlen(s)-i-1;
}
}
bign change(char s[])//将字符串转换为整型
{
bign a;
for(int i=strlen(s)-1; i>=0; i--)
{
if(s[i]!='.')
a.d[a.len++] = s[i]-'0';
}
return a;
}
bign add(bign a, bign b)
{
bign c;
int carry = 0, temp;
for(int i=0; i<a.len||i<b.len; i++)
{
temp = a.d[i] + b.d[i] + carry;
c.d[c.len++] = temp % 10;
carry = temp /= 10;
}
if(carry!=0)
c.d[c.len++]= carry;
return c;
}
int main()
{
int n;
scanf("%d",&n);
getchar();
while(n--)
{
char s1[101], s2[102];
scanf("%s %s", s1, s2);
int len1 = Find(s1),len2 = Find(s2), t=0, pindex;
pindex = max(len1, len2);
if(len1<len2) //len2++
{
t = strlen(s1);
for(int i=0; i<len2-len1; i++)
s1[t++] = '0';
s1[t] = '\0';
}
else //len1 >= len2
{
t = strlen(s2);
for(int i=0; i<len1-len2; i++)
s2[t++] = '0';
s2[t] = '\0';//切记切记切记,字符数组要加'\0'
}
bign a, b;
a = change(s1);
b = change(s2);
bign ans = add(a, b);
for(int i=ans.len-1; i>=pindex; i--)//输出整数部分
printf("%d",ans.d[i]);
printf(".");
//小数部分0~pindex-1
int i;
for(i=0; i<pindex; i++)
{
if(ans.d[i]!=0)
break;
}
for(int j=pindex-1; j>=i;j--)
printf("%d",ans.d[j]);
if(i==pindex)
printf("0");
printf("\n");
getchar();//接受空行
}
return 0;
}
解法七:
#include <cstdio>
#include <string.h>
#include <stdlib.h>
using namespace std;
int n;
char a[105];
char b[105];
char c[105];
int remove(char* a,char c){
char *p;
int pos=0;
int i;
for(p=a,i=strlen(a)-1; *p!=''; p++,i--){
if(*p==c){
pos = i;
char* q;
for(q=p;*q!=''; q++){
*q = *(q+1);
}
}
}
return pos;
}
void add(char* a,char* b,char* c)
{
int i,j,k,max,min,n,temp;
char *s,*pmax,*pmin;
max=strlen(a);
min=strlen(b);
if (max<min)
{
temp=max;
max=min;
min=temp;
pmax=b;
pmin=a;
}
else
{
pmax=a;
pmin=b;
}
s=(char*)malloc(sizeof(char)*(max+1));
s[0]='0';
//相加,不考虑进位
for (i=min-1,j=max-1,k=max;i>=0;i--,j--,k--)
s[k]=pmin[i]-'0'+pmax[j];
//长串的多余的加上去
for (;j>=0;j--,k--)
s[k]=pmax[j];
for (i=max;i>=0;i--)
if (s[i]>'9')
{
s[i]-=10;
s[i-1]++;
}
if (s[0]=='0')
{
for (i=0;i<=max;i++)
c[i-1]=s[i];
c[i-1]='';
}
else
{
for (i=0;i<=max;i++)
c[i]=s[i];
c[i]='';
}
free(s);
}
void addZero(char *a,int n)
{
int len = strlen(a);
int i;
for(i=0; i<n; i++)
{
a[len+i] = '0';
}
a[len+i] = '';
}
void removeLast(char* a)
{
int len = strlen(a);
for(int i=len-1; i>=0; i--)
{
if(a[i]=='0')
a[i] = '';
else
break;
}
}
void addPoint(char* a,int n)
{
int i,j;
for(i=strlen(a),j=0; j<=n; i--,j++)
{
a[i+1] = a[i];
}
a[i+1] = '.';
}
int main()
{
// freopen("1137.in","r",stdin);
// freopen("1137.out","w",stdout);
scanf("%d",&n);
int apos,bpos;
while(n--)
{
scanf("%s %s",a,b);
apos = remove(a,'.');
bpos = remove(b,'.');
if(apos>bpos)
{
addZero(b,apos-bpos);
add(a,b,c);
addPoint(c,apos);
removeLast(c);
printf("%s",c);
}else if(apos<bpos)
{
addZero(a,bpos-apos);
add(a,b,c);
addPoint(c,bpos);
removeLast(c);
printf("%s",c);
}else
{
add(a,b,c);
addPoint(c,apos);
removeLast(c);
printf("%s",c);
}
}
return 0;
}