C语言求方程ax²+bx+c=0的解判断b²-4ac是否等于0为什么是判断它绝对值小于一个人很小的数(如10^-6)

《C程序设计》第五版唐浩强著一书求方程ax²+bx+c=0的解给出的代码中,判断b²-4ac是否等于0是判断它绝对值小于一个人很小的数(如10^-6),他给出的解释是:

   “对于判断b2-4ac是否等于0时,要注意:由于disc(即b2-4ac)是实数,而实数在计算和存储时会有一些微小的误差,因此不能直接进行如下判断:“if(disc==0)…”,因为这样可能会出现本来是零的量,由于上述误差而被判别不等于零而导致结果错误。所以采取的办法是判别disc的绝对值(fabs(disc))是否小于一个很小的数(例如10-6),如果小于此数,就认为disc等于0。“

这里在代码中是小于等于10^-6,这是细节问题。

既然 b²-4ac可能出现本来等于0在计算机中可能却不等于0,那么为什么不会出现本来不等于0在计算机中等于0呢?

还有这里说采取的办法是判别disc的绝对值(fabs(disc))是否小于等于10^-6,本来是0计算机中绝对值有两种情况:可能为0,也可能不为0,但绝对值都小于等于10^-6,这证明计算机是可以存绝对值小于等于10^-6却不等于0的数的,那么会不会出现其他情况:本来不等于0在计算机中的结果绝对值小于等于10^-6的数(自然也不会等于0),比如上述绝对值小于等于10^-6却不等于0的数本身,他们在计算机中可以存储,存起来应该不会有误差,这样有以下情况,本身不等于0,在这个程序却把他认定为0。

判断a是否等于0问题也是这样处理的,a只有存储有可能有误差,没有计算有误差,还有,这里判断b²-4ac是否大于0也是是否大于10^-6,很不理解,希望能够详细解释一下,万分感谢。全部代码如下:

#include <stdio.h>
#include <math.h>
int main()
{
  double a,b,c,disc,x1,x2,realpart,imagpart;
  scanf("%lf,%lf,%lf",&a,&b,&c);
  printf("The equation ");
  if(fabs(a)<=1e-6)
    printf("is not a quadratic\n");
  else
  {
    disc=b*b-4*a*c;
    if(fabs(disc)<=1e-6)
      printf("has two equal roots:%8.4f\n",-b/(2*a));
    else
      if(disc>1e-6)
      {
       x1=(-b+sqrt(disc))/(2*a);
       x2=(-b-sqrt(disc))/(2*a);
       printf("has distinct real roots:%8.4f and %8.4f\n",x1,x2);
      }
      else
      {
       realpart=-b/(2*a);
       imagpart=sqrt(-disc)/(2*a);
       printf(" has complex roots:\n");
       printf("%8.4f+%8.4fi\n",realpart,imagpart);
       printf("%8.4f-%8.4fi\n",realpart,imagpart);
      }
  }
  return 0;
}  

因为计算机有误差,数学值为0的数在计算机中可能是一个很小的数然后10^-6大于这个数就可以控制误差了

比如 0.00000000000001 计算机是判断不了的,你可以判断它的绝对值是否大于0.00000000001(类似这样),控制误差

单个的值得误差小于10的-6次方没错,但是存在四则运算的累进误差。从而使误差放大。因此本来为0的结果不为0了。
用10进制计算为例,假设计算精度为4位有效数,看下面两个计算
0.001+10.01-10.01
因为0.001+10.01=10.011,只能保留4位有效数字,等于10.01,10.01-10.01=0
10.01-10.01+0.001=0+0.001=0.001
如果把上面两个式子分别计算,再相减,也就是计算 (10.01-10.01+0.001) - (0.001+10.01-10.01),数学上等于0,实际上却算出来0.001
虽然单个数字的精度是4位有效数字,但是四则运算后的误差已经使得精度下降到3位了。这还只是加减法,乘法造成的误差更大