系数为0时解二次方程式

时间:2018-09-04 21:46:18

标签: c floating-point double

我遇到了一个写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;
}

3 个答案:

答案 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种情况:

  1. a!= 0: 这是您在代码中处理过的情况。

  2. a == 0 && b!= 0: 这是一个线性方程,其解为x = -c / b

  3. a == 0 && b == 0 && c!= 0:x可能没有值。

  4. 在最后一种情况下,a,b和c等于0:x的解无穷。

编辑:与epsilon的比较被删除了,因为它们似乎没有用

答案 2 :(得分:1)

您的代码中存在一些问题:

  • 您应该检查scanf()的返回值,以避免在无效输入上发生未定义的行为。
  • 您应该将局部变量用于中间结果,以提高代码的可读性
  • 您的printf语句不正确:您应该传递d​​ouble变量的值而不是其地址: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;
}