Games101 作业5 求解一元二次方程

Games101 作业5 易惑点1

求解一元二次方程

在Games101 Ray Tracing的第一份作业中,源码中有一段计算一元二次方程的代码,与数学中的常见求根公式略有不同,这里做一些解释,以方便有类似疑惑的童鞋参考理解:

bool solveQuadratic(const float &a, const float &b, const float &c, float &x0, float &x1)
{
    float discr = b * b - 4 * a * c;
    if (discr < 0) return false;
    else if (discr == 0) x0 = x1 = - 0.5 * b / a;
    else {
        float q = (b > 0) ?
            -0.5 * (b + sqrt(discr)) :
            -0.5 * (b - sqrt(discr));
        x0 = q / a;
        x1 = c / q;
    }
    if (x0 > x1) std::swap(x0, x1);
    return true;
}

求解一元二次方程 a x 2 + b x + c = 0 ax^2+bx+c=0 ax2+bx+c=0,数学上定义其求根公式为:

  1. 计算 Δ = b 2 − 4 a c Δ=b^2-4ac Δ=b24ac
  2. Δ > 0 Δ>0 Δ>0,则存在两个根: x = − b ± b 2 − 4 a c 2 a x=\frac{-b\pm\sqrt{b^2-4ac}}{2a} x=2ab±b24ac
  3. Δ = 0 Δ=0 Δ=0,则存在一个根: x = − b 2 a x=\frac{-b}{2a} x=2ab
  4. Δ < 0 Δ<0 Δ<0,则不存在根

而代码中的解法则略有不同,原因在于Catastrophic cancellation,具体原理现成资料比较多,不重复造轮子,可以参考:
1. PBRT-E3.9-计算误差的分析与管理(一)
2. 关于 C++ 编程的一道题Milo Yip解答
简单来说,就是因为float浮点数存在误差,在一些特殊的情况下,误差会较大,例如两个float a,b数值相近时,则a-b的误差会较大,a+b的误差较小,那么若求根公式中 b b b Δ Δ Δ相近,则其中一个根就会产生较大误差(上述链接2中Milo Yip就做了详细解答),那么为了避免产生误差,就会计算其中一个误差小的根 x 1 x_{1} x1,再根据韦达定理 x 1 ⋅ x 2 = c a x_{1}·x_{2}=\frac{c}{a} x1x2=ac来计算另一个未知根 x 2 x_{2} x2。那么求 x 1 x_{1} x1时采用 + + +还是 − - 呢?

  • Δ > 0 Δ>0 Δ>0时取决于 b b b的正负性:
    1. 当b<=0时,设 q = − b + Δ 2 q=\frac{-b+Δ}{2} q=2b+Δ,则 x 1 = q a x_{1}=\frac{q}{a} x1=aq,根据韦达定理计算 x 2 = c a q a = c q x_{2}= \frac{\frac{c}{a}}{\frac{q}{a}}=\frac{c}{q} x2=aqac=qc
    2. 当b>0时,设 q = − b − Δ 2 q=\frac{-b-Δ}{2} q=2bΔ,则 x 1 = q a x_{1}=\frac{q}{a} x1=aq,根据韦达定理计算 x 2 = c a q a = c q x_{2}= \frac{\frac{c}{a}}{\frac{q}{a}}=\frac{c}{q} x2=aqac=qc
  • Δ = 0 Δ=0 Δ=0时,则 x 1 = x 2 = − b 2 a x_{1}=x_{2}=\frac{-b}{2a} x1=x2=2ab

最后,通过swap确保 x 1 < x 2 x_{1} < x_{2} x1<x2,由上则于代码完成对应。

你可能感兴趣的:(图形学基础,图形学,games101)