Exemplo n.º 1
0
        public static Tuple<List<BigFloat>, List<BigFloat>> Solve(int n, int n_iters, BigFloat tolerance, List<BigFloat> initialGuess, List<BigFloat> zi)
        {
            int m = initialGuess.Count, i, j, k;

            BigFloat d = 0, pa, pb, a, b, qa, qb, k1, k2, k3, na, nb, s1, s2;

            for (i = 0; i < n_iters; ++i)
            {
                d = 0.0;

                for (j = 0; j < m; ++j)
                {
                    //Read in zj
                    pa = initialGuess[j];
                    pb = zi[j];

                    //Compute denominator
                    //
                    //  (zj - z0) * (zj - z1) * ... * (zj - z_{n-1})
                    //

                    a = 1.0;
                    b = 0.0;

                    for (k = 0; k < m; ++k)
                    {
                        if (k == j)
                        {
                            continue;
                        }

                        qa = pa - initialGuess[k];
                        qb = pb - zi[k];
                        if (qa * qa + qb * qb < tolerance)
                        {
                            continue;
                        }

                        k1 = qa * (a + b);
                        k2 = a * (qb - qa);
                        k3 = b * (qa + qb);
                        a = k1 - k3;
                        b = k1 + k2;
                    }

                    //Compute numerator
                    na = RealNumbers[n - 1];
                    nb = ImaginaryNumbers[n - 1];
                    s1 = pb - pa;
                    s2 = pa + pb;
                    for (k = n - 2; k >= 0; --k)
                    {
                        k1 = pa * (na + nb);
                        k2 = na * s1;
                        k3 = nb * s2;
                        na = k1 - k3 + RealNumbers[k];
                        nb = k1 + k2 + ImaginaryNumbers[k];
                    }

                    //Compute reciprocal
                    k1 = a * a + b * b;
                    if (BigFloat.Abs(k1) > Epsilon)
                    {
                        a /= k1;
                        b /= -k1;
                    }
                    else
                    {
                        a = 1.0;
                        b = 0.0;
                    }

                    //Multiply and accumulate
                    k1 = na * (a + b);
                    k2 = a * (nb - na);
                    k3 = b * (na + nb);

                    qa = k1 - k3;
                    qb = k1 + k2;

                    initialGuess[j] = pa - qa;
                    zi[j] = pb - qb;

                    d = BigFloat.Max(d, BigFloat.Max(BigFloat.Abs(qa), BigFloat.Abs(qb)));
                }

                //If converged, exit early
                if (d < tolerance)
                {
                    break;
                }
            }

            // Post process: Combine any repeated roots
            int count;
            for (i = 0; i < m; ++i)
            {

                count = 1;
                a = initialGuess[i];
                b = zi[i];

                for (j = 0; j < m; ++j)
                {
                    if (i == j)
                    {
                        continue;
                    }

                    if (Near(initialGuess[i], zi[i], initialGuess[j], zi[j], tolerance))
                    {
                        ++count;
                        a += initialGuess[j];
                        b += zi[j];
                    }
                }

                if (count > 1)
                {
                    a /= count;
                    b /= count;

                    for (j = 0; j < m; ++j)
                    {
                        if (i == j)
                        {
                            continue;
                        }

                        if (Near(initialGuess[i], zi[i], initialGuess[j], zi[j], tolerance))
                        {
                            initialGuess[j] = a;
                            zi[j] = b;
                        }
                    }

                    initialGuess[i] = a;
                    zi[i] = b;
                }
            }

            for(i=0;i<initialGuess.Count;i++)
            {
                if(BigFloat.Abs(zi[i]) < Epsilon)
                {
                    zi[i] = 0;
                }

                if (BigFloat.Abs(initialGuess[i]) < Epsilon)
                {
                    initialGuess[i] = 0;
                }
            }

            // Order by size
            List<Tuple<BigFloat, BigFloat>> Elements = initialGuess.Zip(zi, (x, y) => Tuple.Create(x, y)).OrderByDescending(x => x.Item2.IsZero()).ToList();

            Elements = Elements.OrderBy(x => x.Item1).ToList();

            // Clear
            zi = new List<BigFloat>();
            initialGuess = new List<BigFloat>();

            for (i = 0; i < Elements.Count; i++)
            {
                bool found = false;

                for (j = 0; j < zi.Count; j++)
                {
                    if (zi[j] == Elements[i].Item2 && initialGuess[j] == Elements[i].Item1)
                    {
                        found = true;
                    }
                }

                if (!found)
                {
                    zi.Add(Elements[i].Item2);
                    initialGuess.Add(Elements[i].Item1);
                }
            }

            // Round the result
            foreach(BigFloat s in initialGuess)
            {
                BigFloat c = new BigFloat(s);
                c.FPart();
                if (BigFloat.Abs(c) < tolerance)
                {
                    s.Floor();
                }
            }

            return new Tuple<List<BigFloat>, List<BigFloat>>(initialGuess, zi);
        }