2023/3/29,4/11:计算加减表达式

原题:

3.7 计算加减表达式语言要求:C++
编写程序,使其能读入并计算一个只包含加减运算的表达式,每一个输入的数据都是浮点数,除第一个数以外,
其余每个数前面都有一个运算符,表达式以分号“;”结束。
例如:
	23+43-233+234;

输入输出格式要求:
	要求输出小数点后6位。
	只输出运算结果,请不要输出其他字符,遇到异常情况(如结尾不是分号等),输出error
例如:
输入:23+43-233+234;回车
输出:67.000000
输入:23+43,回车
输出:error

出现的困难:

        从读入的字符串中提取浮点数,

        当用“从前往后扫描数组用frac*=0.1处理小数部分”的方法时,

        测试用例:12.345678;回车

        输出:12.345677

        回到vs2019中调试,在debug过程中跟踪放小数的变量float frac,发现其总是有“小尾巴”,即

        double frac=0.1;有:

名称类型
frac0.10000000000000001double

        查资料后发现以二进制储存数据的计算机  无法精度较高地储存输入的十进制浮点数。

解决方案:

        ①以整数存储integer和fraction。从前往后扫描,整数部分直接相加,小数部分存储下来。小数部分按最大位数数字后加0补齐位数,以整数部分相加。如最大位数为3,求和后第四位及以上位数的加到整数部分。输出的时候手动输出:   cout<<integer<<"."<<fraction;如果小数部分是负数,则整数部分多减去1,再算(100...00-小数部分)。【也为高精度浮点数专门写一个浮点数类,其成员以分开整数部分和小数部分,以int类型存储。】

        ②直接使用大数加减法,但要以小数点对齐,末位补零。如12.345+5.78-9.123应该如下:

         12 345

        +5 780

        -9 123        

        ————

        +8 997

其中空格为小数点,但可以用整数加减的方式运算。【大数加减那类题目】

测试用例:
输入:23+43-233+234;回车
输出:67.000000

输入:23+43,回车
输出:error

输入:12.345678;回车
输出:12.345678

输入:12.34+5.78-9.123;回车
输出:8.997

输入:12.3456789+1.9999999;回车
输出:14.345679

输入:34.2343+89.345687-12.32+5; 回车

输出:116.259987

(有小数点混杂无小数点)

代码:

#include<iostream>
#include<math.h>
#include<ctype.h>

using namespace std;//命名域声明要写在#include<iostream>后。。。


int main()
{


	char str[50];
	cin >> str;

	int len = strlen(str);
	if (str[len - 1] != ';')
	{
		cout << "error";
		return 0;
	}

	int i;
	int num = 0, sum = 0;
	int sum_decloca = -1, num_decloca = -1;//记录小数点位置,即小数点后有几位数。-1代表还未激活

	int sign = 1;
	if (str[0] == '-')sign = -1;

	for (i = 0; i < len; i++)
	{
		//合法性判断:
		if (!isdigit(str[i]) && str[i] != '+' && str[i] != '-' && str[i] != '.' && str[i] != ';')
		{
			cout << "error";
			return 0;
		}
		if (isdigit(str[i]))
		{
			num = num * 10 + str[i] - '0';
			if (num_decloca != -1)num_decloca++;
		}
		else if (str[i] == '.')
		{
			num_decloca++;
		}
		else //如果是'+'或'-'或 ';'
		{
			if (sum_decloca == num_decloca || sum_decloca == -1)//sum_decloca==-1 demonstrates it is processing the first number
			{

				sum += sign * num;
				if (sum_decloca == -1)sum_decloca = num_decloca;
			}
			else if (sum_decloca > num_decloca)
			{
				//当当前读取的数字num没有小数点:
				if(num_decloca==-1)sum += sign * (double)num * pow(10, ((double)sum_decloca));//当前操作数扩大补零
				//有小数点:
				else sum += sign * (double)num * pow(10, ((double)sum_decloca - (double)num_decloca));//当前操作数扩大补零
				
				sum = (int)sum;
				num_decloca = sum_decloca;
			}
			else
			{
				sum = sum * (int)pow(10, ((double)num_decloca - (double)sum_decloca)) + sign * num;//将sum扩大补零
				sum_decloca = num_decloca;
			}
			//当前的运算符是对下一个数字的,故sign放在加减操作之后
			if (str[i] == '+')sign = 1;
			else if (str[i] == '-')sign = -1;

			//重置:
			num = 0; num_decloca = -1;

		}


	}

	if (sum_decloca == -1)//输入数字全是整型
	{
		cout << sum << ".000000";
	}
	else if (sum_decloca <=6)
	{
		cout << sum / (int)pow(10, (double)sum_decloca) << '.' << sum % (int)pow(10, (double)sum_decloca);
		for (i = 1; i <= 6 - sum_decloca; i++)
		{
			cout << '0';
		}
	}
	else if (sum_decloca > 6)
	{
		sum += 5 * (int)pow(10, (double)(sum_decloca - 6 - 1));//四舍五入
		sum /= (int)pow(10, (double)(sum_decloca - 6));//去掉六位小数以后的数字
		cout << sum / (int)pow(10.0,6.0) << '.' << sum % (int)pow(10.0,6.0);
	}





	return 0;
}

参考:

浮点精度(float、double)运算不精确的原因 - 知乎 (zhihu.com)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值