OJ一元二次方程的根*易错点

20:求一元二次方程的根

  • 查看
  • 提交
  • 统计
  • 提问

总时间限制: 

1000ms

内存限制: 

65536kB

描述

利用公式x1 = (-b + sqrt(b*b-4*a*c))/(2*a), x2 = (-b - sqrt(b*b-4*a*c))/(2*a)求一元二次方程ax2+ bx + c =0的根,其中a不等于0。

输入

输入一行,包含三个浮点数a, b, c(它们之间以一个空格分开),分别表示方程ax2 + bx + c =0的系数。

输出

输出一行,表示方程的解。
若b2 = 4 * a * c,则两个实根相等,则输出形式为:x1=x2=...。
若b2 > 4 * a * c,则两个实根不等,则输出形式为:x1=...;x2 = ...,其中x1>x2。
若b2 < 4 * a * c,则有两个虚根,则输出:x1=实部+虚部i; x2=实部-虚部i,即x1的虚部系数大于等于x2的虚部系数,实部为0时不可省略。实部 = -b / (2*a), 虚部 = sqrt(4*a*c-b*b) / (2*a)

所有实数部分要求精确到小数点后5位,数字、符号之间没有空格。

样例输入

样例输入1
1.0 2.0 8.0

样例输入2
1 0 1

样例输出

样例输出1
x1=-1.00000+2.64575i;x2=-1.00000-2.64575i

样例输出2
x1=0.00000+1.00000i;x2=0.00000-1.00000i

易错点:

        1. 判断两个浮点数相等不能直接用 a == b形式,应该用 a-b> -eps && a-b < eps 形式,eps是很小的数,比如 1e-7

        2. 要避免输出 -0.00000 ,避免办法是自己判断要输出的数足够接近于0了,就直接输出 0.00000

        3. 本题要使用sqrt库函数,要在程序开头加:
        #include         //C语言中的math.h头文件

        sqrt函数用法如下:

        double r = sqrt(5.0); //求5.0的平方根存入r
        double k = sqrt(r); //求r的平方根存入k

        使用 sqrt函数要注意,不要出现求负数平方根的情况

        4. 建议用 double ,不要用float,float精度可能不够

易错点1:关于浮点数相等的判断

        对于int型数据,判断两个数是否相等,我们通常可以用a==b来判断;但是由于计算机存储的原因,判断两浮点数是否相等,只能使用误差范围来判断。可使用 a-b> -eps && a-b < eps 形式或者绝对值fabs(a-b)

区别 用法不同 函数原型不同 包含的头文件不同
abs() 对整数取绝对值 int abs(int x) #include
fabs() 对浮点数取绝对值 double fabs(double x) #include

        具体原因涉及到计组内容,详情请参见一下两篇文章或自行查阅相关文献                                 在程序中如何判断两个浮点数相等 - caicailiu - 博客园

                为什么说比较两个浮点数是否相等是不安全的?_王骕的专栏-CSDN博客

易错点2:避免输出-0的情况

               对浮点数0的除法所得到的值是0还是-0进行探索

#include
#include
using namespace std;

//探究浮点数0和-0在不同情况的除法运算下的输出结果
int main(){

	//分类四类讨论
	int a1 = 0, b1 = -2;
	int a2 = 0, b2 = 2; 
	int a3 = -0, b3 = 2;
	int a4 = -0, b4 = -2;

	double c1 = 0, d1 = -2;
	double c2 = 0, d2 = 2;
	double c3 = -0, d3 = -2; 
	double c4 = -0, d4 = 2;

	cout << setiosflags(ios::fixed) << setprecision(5);

	//输出int和double类型的0和-0
	cout << "输出int型0和-0的值" << endl;
	cout << "a1=" << a1 << " " << "a3=" << a3 << endl;
	cout << "输出int型0和-0的值" << endl;
	cout << "c1=" << c1 << " " << "c3=" << c3 << endl;
	//输出全为0
	cout << endl;
	//作除法运算输出
	cout << "int型各种0和-0的除法结果" << endl;
	cout << "a1/b1=" << a1 / b1 << endl;
	cout << "a2/b2=" << a2 / b2 << endl;
	cout << "a3/b3=" << a3 / b3 << endl;
	cout << "a4/b4=" << a4 / b4 << endl;
	//输出结果全为0
	cout << endl;
	cout << "double型各种0和-0的除法结果" << endl;
	cout << "c1/d1=" << "0/-2=" << c1 / d1 << endl;
	cout << "c2/d2=" << "0/2=" << c2 / d2 << endl;
	cout << "c3/d3=" << "-0/-2=" << c3 / d3 << endl;
	cout << "c4/d4=" << "-0/2=" << c4 / d4 << endl;

	cout << endl;

	if (c3 == c4){
		cout << "0和-0是在数值上是相等的" << endl;
	}

	system("pause");
	return 0;
}

        输出结果如下 :

OJ一元二次方程的根*易错点_第1张图片

         由输出结果可知,0和-0在数值上是相等的,之所以会出现-0的情况,是因为在计算机在二进制运算过程中,数的符号位发生了改变。

        在对于整数的1+7比特的符号数值表示法中,负零是用二进制代码10000000表示的。在8比特二进制反码中,负零是用二进制代码11111111表示。在IEEE 754二进制浮点数算术标准中,指数和尾数为零、符号比特为一的数就是负零。在IBM的普通十进制算数编码规范中,运用十进制来表示浮点数。这里负零被表示为指数为编码内任意合法数值、所有系数均为零、符号比特为一的数。

 易错点3:不要出现负数平方根

        负数是不能开平方的,所以在b*b-4*a*c<0时,求根公式中为了保证根号下的数为正,要写成sqrt(4*a*c-b*b)。

易错点4:浮点数的精度和有效位问题

        对精度和有效位进行探索

#include
#include
using namespace std;

int main(){

	float a = 1.23456789, b = 234.456789123456789123, c = 2.00000000;
	double a1 = 1.23456789, b1 = 234.56789123456789123, c1 = 2.00000000;
	cout << "c=" << c << " " << "c1=" << c1 << endl;
	cout << "b=" << b << " " << "b1=" << b1 << endl;
	cout << "a=" << a << " " << "a1=" << a1 << endl;
	//由输出结果可知,float和double一般都是输出6位有效数字(不包含小数点),多出来的会四舍五入

	cout << endl;
	//保留6位小数
	cout << "保留6位小数" << endl;
	cout << setiosflags(ios::fixed) << setprecision(6);
	cout << "c=" << c << " " << "c1=" << c1 << endl;
	cout << "b=" << b << " " << "b1=" << b1 << endl;
	cout << "a=" << a << " " << "a1=" << a1 << endl;
	//float和double类型的结果一致

	cout << endl;
	cout << "保留7位小数" << endl;
	cout << setiosflags(ios::fixed) << setprecision(7);
	cout << "c=" << c << " " << "c1=" << c1 << endl;
	cout << "b=" << b << " " << "b1=" << b1 << endl;
	cout << "a=" << a << " " << "a1=" << a1 << endl;
	//由输出结果可知,float在设定小数输出位数时,只能精确到小数点后6位

	cout << endl;
	cout << "保留16位小数" << endl;
	cout << setiosflags(ios::fixed) << setprecision(16);
	cout << "c=" << c << " " << "c1=" << c1 << endl;
	cout << "b=" << b << " " << "b1=" << b1 << endl;
	cout << "a=" << a << " " << "a1=" << a1 << endl;
	//由输出结果可知,double在设定小数输出位数时,只能精确到小数点后15位

	cout << endl;
	//探究float和double的有效位数
	cout << setiosflags(ios::fixed) << setprecision(20);
	cout << "探究float和double的有效位数" << endl;
	float x = 123456789.123456789;
	double y = 123456789.123456789;
	double z = 0.123456789123456789;
	float z1 = 0.123456789123456789;
	cout << z << endl;
	cout << z1 << endl;
	cout << "x=" << x << " " << "y=" << y << endl;

	system("pause");
	return 0;
}

 OJ一元二次方程的根*易错点_第2张图片

 总结:
(1)float和double在默认情况下输出6位有效数字(不包含小数点)
(2)float可以精确到小数点后6为(小数点前为0的情况下可精确到7位),double能够精确到小数点后16位(小数点前为0的情况下可精确到17位)
(3)float的有效位为6,double的有效位为16

程序AC代码:

#include
#include
#include
#define eps 1e-7
using namespace std;

//这里直接使用if语句了,没有使用函数实现模块化,请见谅
int main(){

	double a, b, c, image, real, x1, x2;
	cin >> a >> b >> c;
	cout << setiosflags(ios::fixed) << setprecision(5);
	
	//德塔等于0
	if (b*b == 4 * a*c){
		x1 = x2 = (-b) / (2 * a);
		if (fabs(x1 - 0)< eps){
			x1 = 0;
			x2 = 0;
		}
		cout << "x1=x2=" << x1 << endl;
	}

	//德塔大于0
	else if (b*b > 4 * a*c){
		real = -b / (2 * a);
		image = sqrt(b*b - 4 * a*c) / (2 * a);

		//判断-0的情况,赋值0避免
		x1 = real + image;
		if (fabs(x1 - 0)< eps){
			x1 = 0;
		}
		//判断-0的情况,赋值0避免
		x2 = real - image;
		if (fabs(x2 - 0)< eps){
			x2 = 0;
		}
		cout << "x1=" << x1 << ";" << "x2=" << x2 << endl;
	}
	
	//德塔小于0
	else{
		real = (-b) / (2 * a);
		//判断-0的情况,赋值0避免
		if (fabs(real-0)< eps){
			real = 0;
		}
		image = sqrt(4 * a*c - b*b) / (2 * a);	//注意平方根下的数必须为正
		cout << "x1=" << real << "+" << image << "i" << ";";
		cout << "x2=" << real << "-" << image << "i" << endl;

	}

	system("pause");
	return 0;
}

你可能感兴趣的:(算法,c++)