我遇到了一个写C程序的问题,该程序可以解决方程 ax 2 + bx + c = 0 ,其中 a , b 和 c 是double
类型的系数。任何系数都可以为零。在这个问题上,我不清楚如何处理double
变量。
这是我的代码。就目前而言,我知道我的程序无法区分两个根和无限多个根。它还不会检测“线性方程情况”。如何使它检测到无限数量的解决方案?如果b> 0,则在注释中还建议我先用负号计算出根,然后再使用Viet定理。我了解这是因为将两个数字相加总是更准确。我还猜想我应该做与b <0完全相反的事情。但是如果b == 0怎么办?在这种情况下,该程序将不执行任何操作。还是我应该在b <0中包含b == 0并让b <= 0?
#include <stdio.h>
#include <math.h>
#include <float.h>
int main() {
double a, b, c, x1, x2;
scanf("%lf", &a);
scanf("%lf", &b);
scanf("%lf", &c); // just reading variables
//ax^2+bx+c=0
if ((b * b - 4 * a * c) < 0) {
printf("no");
} else {
x1 = (-b + sqrt(b * b - 4 * a * c)) / (2 * a); //calculating roots
x2 = (-b - sqrt(b * b - 4 * a * c)) / (2 * a);
if ((fabs((a * x1 * x1 + b * x1 + c)) < DBL_EPSILON) & (fabs((a * x2 * x2 + b * x2 + c)) < DBL_EPSILON)) { //plugging the roots in
if (fabs((x1 - x2)) < DBL_EPSILON) { //checking if the roots are equal
printf("%lf", &x1); // if they are equal, we print only one of them
} else {
printf("%lf", &x1); // if they are not equal, we print both.
printf("\n %lf", &x2);
}
} else { // if there are no two valid roots
if ((fabs((a * x1 * x1 + b * x1 + c)) < DBL_EPSILON)) // we try to find one root.
printf("%lf", &x1);
if (fabs((a * x2 * x2 + b * x2 + c)) < DBL_EPSILON)
printf("%lf", &x2);
if ((fabs((a * x1 * x1 + b * x1 + c)) > DBL_EPSILON) & (fabs((a * x2 * x2 + b * x2 + c)) > DBL_EPSILON)) // if both of the plugged roots don't satisfy the equation
printf("no");
}
}
return 0;
}
答案 0 :(得分:2)
求解系数为0的二次方程式
我如何使它检测到无限数量的解决方案?
a==0 && b == 0 && c == 0
时。
这段代码中的任何地方都不需要DBL_EPSILON
。另请参见@Eric Postpischil。
但是如果b == 0怎么办?
if (b == 0) { // y = a*x*x + c
if (a) {
double dd = -c/a;
if (dd >= 0) {
double d = sqrt(d);
printf_roots("+/- roots", d,-d);
} else {
printf_roots("Complex roots", NAN, NAN); // Note NAN may not exist
}
} else if (c) { // y = 0*x*x + c, c != 0
printf_roots("No roots", NAN, NAN);
} else { // y = 0*x + 0
printf_roots("Infinite roots", -HUGE_VAL, HUGE_VAL);
}
或者我应该在b <0中包含b == 0并让b <= 0吗?
除非b==0
的编码目标需要特殊输出,否则我只会在b==0
发生时对a==0
进行矢量编码作为子测试。
if (a==0) {
if (b == 0) {
与许多FP代码一样,二次方程很容易溢出并达到0,这两种情况都失去了所有的精度。
请考虑以下代码:不必要的减法可能导致溢出或截断为0,而第二次可能不会。这取决于很多事情。
if ((b * b - 4 * a * c) < 0)
//
if (b * b < 4 * a * c)
此外,C允许使用更广泛的数学方法进行各种计算。研究FLT_EVAL_METHOD
。因此,为了防止sqrt(value_less_than_0)
,代码应计算discriminate,然后测试将要应用于x
的对象sqrt(x)
。
//if ((b * b - 4 * a * c) < 0) {
// printf("no");
//} else {
// x1 = (-b + sqrt(b * b - 4 * a * c))
double discriminate = b * b - 4 * a * c;
if (discriminate < 0) {
printf("no");
} else {
double d = sqrt(discriminate);
x1 = (-b + d)
关于“如果b> 0,则在判别式前用负号计算根,然后使用Viet定理”的想法,我建议提高保留精度,在此以下不像有符号值相减。
double d = sqrt(discriminate);
// Note x1*x2 = c/a
if (b < 0) {
x2 = (-b + d)/(2*a);
x1 = c/a/x2;
} else {
x1 = (-b - d)/(2*a);
x2 = c/a/x1;
}
printf_roots("2 roots", x1, x2);
关于printf("%lf", &x1);
的注释。您未在启用所有警告的情况下进行编译。节省时间-启用它们。应该为printf("%lf", x1);
否&
。
另外double
是浮点数。对于FP代码开发,请使用"%e"
,"%a"
或"%g"
完整地查看重要信息。
printf("%g\n", some_double);
// or better
printf("%.*e\n", DBL_DECIMAL_DIG -1, some_double);
答案 1 :(得分:1)
由于不允许除以零,因此您必须将问题分为4种情况:
a!= 0: 这是您在代码中处理过的情况。
a == 0 && b!= 0: 这是一个线性方程,其解为x = -c / b
a == 0 && b == 0 && c!= 0:x可能没有值。
在最后一种情况下,a,b和c等于0:x的解无穷。
编辑:与epsilon的比较被删除了,因为它们似乎没有用
答案 2 :(得分:1)
您的代码中存在一些问题:
scanf()
的返回值,以避免在无效输入上发生未定义的行为。您的printf
语句不正确:您应该传递double变量的值而不是其地址:printf("%lf", &x1);
应该读为:
printf("%f", x1);
关于退化的情况,您应该先进行测试,然后再尝试求解二次度方程。
这是更正的版本:
#include <stdio.h>
#include <math.h>
int main() {
double a, b, c, delta, x1, x2;
if (scanf("%lf%lf%lf", &a, &b, &c) != 3) {
printf("invalid input\n");
return 1;
}
if (a == 0) {
// not a quadratic equation
if (b != 0) {
printf("one solution: %g\n", -c / b);
} else {
if (c != 0) {
printf("no solution\n");
} else {
printf("all real values are solutions\n");
}
}
} else {
delta = b * b - 4 * a * c;
if (delta < 0) {
printf("no real solution\n");
} else
if (delta == 0) {
printf("one double solution: %g\n", -b / (2 * a));
} else {
x1 = (-b + sqrt(delta)) / (2 * a);
x2 = (-b - sqrt(delta)) / (2 * a);
printf("two solutions: %g, %g\n", x1, x2);
}
}
return 0;
}