C++ 一元二次方程求根,直输方程可含分数(附源码、注释)

写在前面:翻看以前做的程设题,偶然看到这个期末考没做出来的硬茬(当时是一元一次求根),重新写了个升级版,弥补一下遗憾。 

力扣题库“求解方程”可过,改一下函数名即可。

目录

格式控制

输入格式

输出格式

系数获取

符号判断

根的计算

源码及注释

格式控制

考虑到力扣里面有一个情况是“0x=0”,系数可以是0,还有输出的时候若根是整数应该不带小数点,代码进行了整型判断,控制了格式。

输入格式

系数写在x前面,若是分数则按"分子/分母"形式写,x后面只可有两种数字,1或2,分别代表一次幂和二次幂,不写就默认一次幂。

输入格式具有包容性,是利用string实现的,比如"0/4x2+32x1-x-0+1-1/1=+55-22+33-4/2x"这样写也可以,简化后就是"33x-66=0"此时只有一解是x=2。

暂不支持括号()和乘*运算,除/运算也只支持系数和常数,系数及常数不支持超大数,欢迎小伙伴们提提点子。

输出格式

若二次项系数为0,则输出"x=...",不为0,输出"x1=... x2=...",可以在函数后面找return修改输出格式。"No solution"表示无解,"Infinite solutions"表示有无穷解。

可修改:若输入规范,比如只输入a(二次项系数),b(一次项系数),c(常数项),代码将num1赋值b,num2赋值a,num3赋值c即可,函数里的符号判断都可去掉。

系数获取

按位读取string s,把数存进temp,考虑符号。设置fu1判断前面符号是“+”还是“-”,fu2判断读取位置的等式左右,右边统一*-1来实现将右式移到左边计算。读取时前一位也是数字便将保存的值*10再进行相加,以实现保存多位数字。加入flag判断是否出现分数,若有则保存分子值到save,再除以分号后分母的值,然后将分数的值存进temp中。

if (isdigit(*(p + i))) {
			if (!i)temp += *(p + i) - '0';
			else if (!isdigit(*(p + i - 1))) {
					temp += (*(p + i) - '0') * fu1 * fu2;
				if (!isdigit(s[i+1]) && flag) {
					temp = save / temp;
					save = 0;
					flag = 0;
				}
			}
			else {
				temp = temp * 10 + (*(p + i) - '0') * fu1 * fu2;  //移位后加的数也要考虑符号
				if (!isdigit(s[i+1]) && flag) {
					temp = save / temp;
					save = 0;
					flag = 0;
				}
			}
		}
		else if (*(p + i) == 'x') {
			if (s[i+1] == '2') {                                   //考虑2次,越界问题有'\0'不怕
				if (!i)num2 = 1;
				else if (!isdigit(*(p + i - 1)))num2 += fu1 * fu2; //怕系数是0,cornercase
				else {
					num2 += temp;
					temp = 0;
				}
				i++;
			}
			else {                                                   //1次
				if (!i)num1 = 1;
				else if (!isdigit(*(p + i - 1)))num1 += fu1 * fu2;   //怕系数是0
				else {
					num1 += temp;
					temp = 0;
				}
				if (s[i + 1] == '1')i++;                             //考虑1次幂
			}
		}

可以看到,当读到“x”,经判断后将temp值累加到相应次数项的系数中,num1、num2分别保存一次项、二次项系数。

符号判断

else if (*(p + i) == '=') {                                  //符号变,temp清零
			if (temp)num3 += temp;
			fu1 = 1;
			fu2 = -1;
			temp = 0;
		}
		else if (*(p + i) == '-') {
			if (temp)num3 += temp;
			fu1 = -1;
			temp = 0;
		}
		else if (*(p + i) == '+') {
			if (temp)num3 += temp;
			fu1 = 1;
			temp = 0;
		}
		else if (*(p + i) == '/') {                                  //考虑分数
			save = fabs(temp);
			temp = 0;
			flag = 1;
		}
	}
	num3 += temp;

每次读到符号,除了符号的改变,若temp值没有保存到各项系数中,则累加至常数项num3,注意末尾要再加一次。

根的计算

二次项系数为0,则变为解一元一次方程,只返回“x=...”,计算只需-num3/num1即可,对结果加入了精确到小数点后六位的整形判断,如果是整数解,则不带小数点规范输出。

二次项系数不为0,有两解,利用求根公式,返回“x1=... x2=...",对结果加入了精确到小数点后六位的整形判断,如果是整数解,则不带小数点规范输出。

if (num2 == 0) {                                                 //2次项系数为0情况
		if (!num1 && num3)return "No solution";                      //无解
		else if (!num1 && !num3)return "Infinite solutions";         //无穷解
		else
			if (fabs(fabs(num3 / num1) - int(fabs(num3 / num1) + 0.5)) < 0.000001) {         //判断能否用整数表示答案
				int x, flag1 = 1;                                    //符号判断
				if (-num3 / num1 < 0)flag1 = -1;
				x = int(fabs(num3 / num1) + 0.5)*flag1;
				return "x=" + to_string(x);
			}
			else return "x=" + to_string(-num3  / num1);
	}
	else {
		double delta = num1 * num1 - 4 * num2 * num3;
		if (delta < 0)return "No solution";
		else {
			double x1 = (-num1 + sqrt(delta)) / (2 * num2), x2 = (-num1 - sqrt(delta)) / (2 * num2); //求根公式
			if (fabs(fabs(x1) - int(fabs(x1) + 0.5)) < 0.000001 && fabs(fabs(x2) - int(fabs(x2) + 0.5)) < 0.000001) { //判断能否用整数表示答案
				int tx1, tx2, flag2 = 1, flag3 = 1;                  //符号判断
				if (x1 < 0)flag2 = -1;
				if (x2 < 0)flag2 = -1;
				tx1 = int(fabs(x1) + 0.5) * flag2;
				tx2 = int(fabs(x2) + 0.5) * flag3;
				return "x1=" + to_string(tx1) + " x2=" + to_string(tx2);
			}
			else return "x1=" + to_string(x1) + " x2=" + to_string(x2);
		}
	}

源码及注释

​#include <iostream>
#include <string>
#include <cmath>
using namespace std;
string Solution(string& s) {                                    
	string::iterator p = s.begin(), end = s.end();
	double temp = 0, num1 = 0, num2 = 0, num3 = 0; //num1是一次系数,2是二次,3常数,temp作为暂时数
	int flag = 0, save = 0, fu1 = 1, fu2 = 1;//flag判断有无分数,save保存分子,fu1判断符号,fu2判断等式左右,右边统一换号
	for (int i = 0; p + i != end; i++) {
		if (isdigit(*(p + i))) {
			if (!i)temp += *(p + i) - '0';
			else if (!isdigit(*(p + i - 1))) {
					temp += (*(p + i) - '0') * fu1 * fu2;
				if (!isdigit(s[i+1]) && flag) {
					temp = save / temp;
					save = 0;
					flag = 0;
				}
			}
			else {
				temp = temp * 10 + (*(p + i) - '0') * fu1 * fu2; //移位后加的数也要考虑符号
				if (!isdigit(s[i+1]) && flag) {
					temp = save / temp;
					save = 0;
					flag = 0;
				}
			}
		}
		else if (*(p + i) == 'x') {
			if (s[i+1] == '2') {             //考虑2次,越界问题有'\0'不怕
				if (!i)num2 = 1;
				else if (!isdigit(*(p + i - 1)))num2 += fu1 * fu2; //考虑系数可能是0
				else {
					num2 += temp;
					temp = 0;
				}
				i++;
			}
			else {                                   //1次项系数处理
				if (!i)num1 = 1;
				else if (!isdigit(*(p + i - 1)))num1 += fu1 * fu2; //考虑系数可能是0
				else {
					num1 += temp;
					temp = 0;
				}
				if (s[i + 1] == '1')i++;             //考虑1次幂
			}
		}
		else if (*(p + i) == '=') {                  //遇"="符号变,temp清零
			if (temp)num3 += temp;
			fu1 = 1;
			fu2 = -1;
			temp = 0;
		}
		else if (*(p + i) == '-') {
			if (temp)num3 += temp;
			fu1 = -1;
			temp = 0;
		}
		else if (*(p + i) == '+') {
			if (temp)num3 += temp;
			fu1 = 1;
			temp = 0;
		}
		else if (*(p + i) == '/') {                    //考虑分数
			save = fabs(temp);
			temp = 0;
			flag = 1;
		}
	}
	num3 += temp;
	if (num2 == 0) {                                   //只有1次项情况
		if (!num1 && num3)return "No solution";             //无解
		else if (!num1 && !num3)return "Infinite solutions";  //无穷解
		else
			if (fabs(fabs(num3 / num1) - int(fabs(num3 / num1) + 0.5)) < 0.000001) {         //判断能否用整数表示答案
				int x, flag1 = 1;                          //符号判断
				if (-num3 / num1 < 0)flag1 = -1;
				x = int(fabs(num3 / num1) + 0.5)*flag1;
				return "x=" + to_string(x);
			}
			else return "x=" + to_string(-num3  / num1);
	}
	else {
		double delta = num1 * num1 - 4 * num2 * num3;
		if (delta < 0)return "No solution";
		else {
			double x1 = (-num1 + sqrt(delta)) / (2 * num2), x2 = (-num1 - sqrt(delta)) / (2 * num2); //求根公式
			if (fabs(fabs(x1) - int(fabs(x1) + 0.5)) < 0.000001 && fabs(fabs(x2) - int(fabs(x2) + 0.5)) < 0.000001) {                         //判断能否用整数表示答案
				int tx1, tx2, flag2 = 1, flag3 = 1;            //符号判断
				if (x1 < 0)flag2 = -1;
				if (x2 < 0)flag2 = -1;
				tx1 = int(fabs(x1) + 0.5) * flag2;
				tx2 = int(fabs(x2) + 0.5) * flag3;
				return "x1=" + to_string(tx1) + " x2=" + to_string(tx2);
			}
			else return "x1=" + to_string(x1) + " x2=" + to_string(x2);
		}
	}
}
int main() {
	string s;
	cin >> s;
	cout << Solution (s);
	return 0;
}

​

​

欢迎大家进行测试,若能指出其中错误或可优化处十分感激,你们的反馈就是我创作的动力。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JUICYYY33

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值