【问题标题】:Newton's Method for finding Complex Roots in Java牛顿法在 Java 中求复根
【发布时间】:2015-07-28 17:14:29
【问题描述】:

我的 Java 类中有一个项目,但遇到了问题。 该项目基本上是在屏幕上标记坐标,用它们制作一个(复杂的)多项式,然后使用牛顿法使用随机猜测求解多项式,并在屏幕上绘制猜测的路径。 我对任何绘图、标记等都没有问题。 但由于某种原因,我的牛顿法算法随机漏了根。有时它没有击中它们,有时它错过了一两个。我已经改变了几个小时的东西,但我真的想不出一个解决方案。 当一个根丢失时,通常我在数组中得到的值要么收敛到无穷大或负无穷大(非常高的数字) 任何帮助将不胜感激。

> // Polynomial evaluation method.  
   public Complex evalPoly(Complex complexArray[], Complex guess) {
        Complex result = new Complex(0, 0);
        for (int i = 0; i < complexArray.length; i++) {
            result = result.gaussMult(guess).addComplex(complexArray[complexArray.length - i - 1]);
        }
        return result;
    }

> // Polynomial differentation method.
    public Complex[] diff(Complex[] comp) {
        Complex[] result = new Complex[comp.length - 1];
        for (int j = 0; j < result.length; j++) {
            result[j] = new Complex(0, 0);
        }
        for (int i = 0; i < result.length - 1; i++) {
            result[i].real = comp[i + 1].real * (i + 1);
            result[i].imaginary = comp[i + 1].imaginary * (i + 1);
        }
        return result;
    }

> // Method which eliminates some of the things that I don't want to go into the array
    public boolean rootCheck2(Complex[] comps, Complex comp) {
        double accLim = 0.01;
        if (comp.real == Double.NaN)
            return false;
        if (comp.real == Double.NEGATIVE_INFINITY || comp.real == Double.POSITIVE_INFINITY)
            return false;
        if (comp.imaginary == Double.NaN)
            return false;
        if (comp.imaginary == Double.NEGATIVE_INFINITY || comp.imaginary == Double.POSITIVE_INFINITY)
            return false;
        for (int i = 0; i < comps.length; i++) {
            if (Math.abs(comp.real - comps[i].real) < accLim && Math.abs(comp.imaginary - comps[i].imaginary) < accLim)
                return false;
        }
        return true;
    }

> // Method which finds (or attempts) to find all of the roots
  public Complex[] addUnique2(Complex[] poly, Bitmap bitmapx, Paint paint, Canvas canvasx) {
        Complex[] rootsC = new Complex[poly.length - 1];
        int iterCount = 0;
        int iteLim = 20000;
        for (int i = 0; i < rootsC.length; i++) {
            rootsC[i] = new Complex(0, 0);
        }
        while (iterCount < iteLim && MainActivity.a < rootsC.length) {
            double guess = -492 + 984 * rand.nextDouble();
            double guess2 = -718 + 1436 * rand.nextDouble();
            if (rootCheck2(rootsC, findRoot2(poly, new Complex(guess, guess2), bitmapx, paint, canvasx))) {
                rootsC[MainActivity.a] = findRoot2(poly, new Complex(guess, guess2), bitmapx, paint, canvasx);
                MainActivity.a = MainActivity.a + 1;
            }
            iterCount = iterCount + 1;
        }
        return rootsC;
    }

> // Method which finds a single root of the complex polynomial.
    public Complex findRoot2(Complex[] comp, Complex guess, Bitmap bitmapx, Paint paint, Canvas canvasx) {
        int iterCount = 0;
        double accLim = 0.001;
        int itLim = 20000;
        Complex[] diffedComplex = diff(comp);
        while (Math.abs(evalPoly(comp, guess).real) >= accLim && Math.abs(evalPoly(comp, guess).imaginary) >= accLim) {
            if (iterCount >= itLim) {
                return new Complex(Double.NaN, Double.NaN);
            }
            if (evalPoly(diffedComplex, guess).real == 0 || evalPoly(diffedComplex, guess).imaginary == 0) {
                return new Complex(Double.NaN, Double.NaN);
            }
            iterCount = iterCount + 1;
            guess.real = guess.subtractComplex(evalPoly(comp, guess).divideComplex(evalPoly(diffedComplex, guess))).real;
            guess.imaginary = guess.subtractComplex(evalPoly(comp, guess).divideComplex(evalPoly(diffedComplex, guess))).imaginary;
            drawCircles((float) guess.real, (float) guess.imaginary, paint, canvasx, bitmapx);
        }
        return guess;
    }

> // Drawing method
    void drawCircles(float x, float y, Paint paint, Canvas canvasx, Bitmap bitmapx) {
        canvasx.drawCircle(x + 492, shiftBackY(y), 5, paint);
        coordPlane.setAdjustViewBounds(false);
        coordPlane.setImageBitmap(bitmapx);
    }

}

【问题讨论】:

  • 应该注意== Double.NaN总是假的。您应该使用Double.isNan(double) 来查看值是否为 NaN。
  • 所以它是在随机猜测,而你错过了根源?这并不奇怪。你在 x 处暗中试探。牛顿法的工作原理是查看一个产生正 y 的 x 和另一个产生负 y 的 x,然后对差进行二等分。
  • @rajah9 这就是我们被教导的方式。同样的方法对正态多项式没有问题。随机猜测总是最终会收敛到一个根。我很难理解你所说的第二部分的意思,一个例子将不胜感激。
  • @Obicere 注意,谢谢!
  • @rajah9:这就是二分法。虽然它像推土机一样坚固,但如果条件适用,它也一样慢。牛顿是法拉利,处理起来可能更精致,但速度也快了很多。 -- 此外,二分法并不容易应用于复平面上的函数。

标签: java newtons-method


【解决方案1】:

错误 1

线条

guess.real = guess.subtractComplex(evalPoly(comp, guess).divideComplex(evalPoly(diffedComplex, guess))).real;
guess.imaginary = guess.subtractComplex(evalPoly(comp, guess).divideComplex(evalPoly(diffedComplex, guess))).imaginary;

首先引入一个不必要的复杂性,然后引入一个使其偏离牛顿方法的错误。第二行中使用的guess 与第一行中使用的guess 不同,因为实部已更改。

你为什么不使用,比如在评估过程中,复杂的赋值

guess = guess.subtractComplex(evalPoly(comp, guess).divideComplex(evalPoly(diffedComplex, guess)));

错误 2(更新)

在微分多项式的计算中,您缺少

中的最高次数项
for (int i = 0; i < result.length - 1; i++) {
   result[i].real = comp[i + 1].real * (i + 1);
   result[i].imaginary = comp[i + 1].imaginary * (i + 1);

应该是i &lt; result.lengthi &lt; comp.length - 1。使用错误的导数当然会导致迭代中出现不可预知的结果。


关于根边界和初始值

您可以为每个多项式分配一个外部根边界,例如

R = 1+max(abs(c[0:N-1]))/abs(c[N])

在这个圆上或附近使用3*N点,随机或等距,应该会增加到达每个根的概率。

但是找到所有根的常用方法是使用多项式紧缩,即拆分对应于已找到的根近似值的线性因子。然后使用完整多项式执行几个额外的牛顿步可恢复最大精度。


牛顿分形

每个根都有一个盆地或吸引域,域之间有分形边界。在重建与

中使用的情况类似的情况

我计算了一个牛顿分形,表明对两个根的吸引力和对另外两个根的无知是其背后的数学特征,而不是实现牛顿方法的错误。

相同颜色的不同阴影属于同一根的域,其中亮度对应于到达根周围白色区域的步数。

【讨论】:

  • 原来是这样的,我想我后来改变了它来测试一些东西,然后就这样了。可悲的是,结果还是一样。我将链接应用程序的图像。带有黑点的圆圈是未找到的根。 imgur.com/v9ncxT3
  • 您能否通过颜色或大小强调迭代的初始点?或者用线连接每次迭代的点?每个根部都有一个盆地或吸引域,其中包含围绕根部的圆盘,并且通常具有所有盆地混合的分形边界,正如您可以通过查找“牛顿分形”看到的那样。
  • 感谢您提供信息丰富的回复!我需要一段时间才能阅读和理解所有内容,有时数学真的不是我的事。在这张图片中,最初的猜测是较大的粉红色圆圈。 imgur.com/HqDn8WU
  • 我这样做是为了让程序获取所有给定 X 和 Y 值的最大值和最小值,以及这些数字之间的随机值。我仍然缺少很多根。 imgur.com/eV3mT1O
  • 我尝试的最后一件事是为每个根单独选择非常接近的随机值。即使最初的猜测距离根有像素,有时也无法收敛。imgur.com/vY7BuR3
猜你喜欢
  • 2019-06-27
  • 1970-01-01
  • 2013-10-17
  • 1970-01-01
  • 1970-01-01
  • 2012-10-02
  • 2022-01-10
  • 1970-01-01
  • 2012-10-24
相关资源
最近更新 更多