コード例 #1
0
        private double RootWithBisection(double a0, double b0)
        {
            var normal = this.Normalize();
            var a      = a0;
            var b      = b0;

            while (!Approximation.EqualDoubles(a, b, normal.Deg))
            {
                var c      = (b / 2) + (a / 2);
                var cValue = normal.Value(c);
                if (Approximation.EqualDoubles(cValue, 0, normal.Deg))
                {
                    return(c);
                }

                if (Math.Sign(normal.Value(a)) == Math.Sign(cValue))
                {
                    a = c;
                }
                else
                {
                    b = c;
                }
            }

            return((a + b) / 2);
        }
コード例 #2
0
        /// <summary>
        /// Количество знакоперемен в ряде Штурма
        /// </summary>
        /// <param name="series">Ряд Штурма</param>
        /// <param name="x">Точка, в которой вычисляются знакоперемены.</param>
        /// <returns></returns>
        public static int NumberOfResigns(List <Polynomial> series, double x)
        {
            var i0 = 0;

            while (Approximation.EqualDoubles(series[i0].Value(x), 0, series[i0].Deg) && i0 < series.Count)
            {
                i0++;
            }

            var lastSign = Math.Sign(series[i0].Value(x));
            var result   = 0;

            for (var i = i0 + 1; i < series.Count; i++)
            {
                var value = series[i].Value(x);
                if (Approximation.EqualDoubles(value, 0, series[i].Deg))
                {
                    continue;
                }

                var nextSign = Math.Sign(value);
                if (lastSign != nextSign)
                {
                    result++;
                    lastSign = nextSign;
                }
            }

            if (lastSign < 0 && series.Last() == Nullear)
            {
                result++;
            }

            return(result);
        }
コード例 #3
0
        private static IEnumerable <double> Shturm(List <Polynomial> series, double a, double b)
        {
            var result = new List <double>();

            if (Approximation.EqualDoubles(a, b, series[0].Deg))
            {
                return(result);
            }

            var aN = NumberOfResigns(series, a);
            var bN = NumberOfResigns(series, b);
            var n  = aN - bN;

            if (n > 1)
            {
                var c = (a + b) / 2;
                if (Approximation.EqualDoubles(series[0].Value(c), 0, series[0].Deg))
                {
                    result.Add(c);
                }
                else
                {
                    var listA = Shturm(series, a, c);
                    var listB = Shturm(series, c, b);

                    result.AddRange(listA);
                    result.AddRange(listB);
                }

                for (var i = 0; i < result.Count - 1; i++)
                {
                    for (var j = i + 1; j < result.Count; j++)
                    {
                        if (Approximation.EqualDoubles(result[i], result[j], (int)Math.Pow(series[0].Deg, 4)))
                        {
                            result.RemoveAt(j);
                        }
                    }
                }

                return(result);
            }

            if (n != 1)
            {
                return(result);
            }

            var root = series[0].RootWithBisection(a, b);

            if (!Approximation.EqualDoubles(a, root, series[0].Deg) &&
                !Approximation.EqualDoubles(root, b, series[0].Deg))
            {
                result.Add(root);
            }

            return(result);
        }
コード例 #4
0
        /// <summary>
        /// Создает новый полином, являющийся остатком от деления этого полинома на другой.
        /// </summary>
        /// <param name="other">Другой полином, на который необходимо разделить.</param>
        /// <returns></returns>
        public Polynomial Rest(Polynomial other)
        {
            var div1 = this;
            var div2 = other;

            while (div1.Deg >= div2.Deg)
            {
                var shift = div1.Deg - div2.Deg;
                var koef  = div1[div1.Deg] / div2[div2.Deg];
                var div3  = new Polynomial(new double[div1.Deg]);

                for (var i = div1.Deg - 1; i >= shift; i--)
                {
                    div3[i] = div1[i] - koef * div2[i - shift];
                }

                for (var i = shift - 1; i >= 0; i--)
                {
                    div3[i] = div1[i];
                }

                div1 = div3;
            }

            if (Approximation.EqualDoubles(div1[div1.Deg], 0, this.Deg) && div1.Deg > 0)
            {
                var shift = 1;
                while (Approximation.EqualDoubles(div1[div1.Deg - shift], 0, this.Deg))
                {
                    shift++;
                    if (shift == div1.Deg)
                    {
                        return(Nullear);
                    }
                }

                var newResult = new Polynomial(new double[div1.Deg + 1 - shift]);
                for (var i = div1.Deg - shift; i >= 0; i--)
                {
                    newResult[i] = div1[i];
                }

                div1 = newResult;
            }

            for (var i = 0; i <= div1.Deg; i++)
            {
                div1[i] *= -1;
            }

            return(div1);
        }
コード例 #5
0
        private double RootWithBisection()
        {
            var normal = this;

            if (!Approximation.EqualDoubles(normal[normal.Deg], 1, normal.Deg))
            {
                normal = normal.Normalize();
            }

            var maxRootValue = 0d;

            for (var i = normal.Deg - 1; i >= 0; i--)
            {
                maxRootValue += Math.Abs(normal[i]);
            }

            var a = -maxRootValue;

            if (Approximation.EqualDoubles(normal.Value(a), 0, normal.Deg))
            {
                return(a);
            }

            var b = maxRootValue;

            if (Approximation.EqualDoubles(normal.Value(b), 0, normal.Deg))
            {
                return(b);
            }

            while (!Approximation.EqualDoubles(a, b, normal.Deg))
            {
                var c      = (b + a) / 2;
                var cValue = normal.Value(c);
                if (Approximation.EqualDoubles(cValue, 0, normal.Deg))
                {
                    return(c);
                }

                if (Math.Sign(normal.Value(a)) == Math.Sign(cValue))
                {
                    a = c;
                }
                else
                {
                    b = c;
                }
            }

            return((a + b) / 2);
        }
コード例 #6
0
        /// <summary>
        /// Находит все различные положительные корни.
        /// </summary>
        /// <returns></returns>
        public List <double> RootsWithSturm()
        {
            var result = new List <double>();

            if (Math.Abs(this[0]) < double.Epsilon * this.Deg)
            {
                result.Add(0);
            }

            var normal = this.Normalize();

            var maxRootValue = 0d;

            for (var i = normal.Deg - 1; i >= 0; i--)
            {
                maxRootValue += Math.Abs(normal[i]);
            }

            var a = -maxRootValue;

            if (Approximation.EqualDoubles(normal.Value(a), 0, normal.Deg))
            {
                result.Add(a);
            }

            var b = maxRootValue;

            if (Approximation.EqualDoubles(normal.Value(b), 0, normal.Deg))
            {
                result.Add(b);
            }

            var sturm     = new List <Polynomial>();
            var lastSturm = normal;

            sturm.Add(lastSturm);
            var nextSturm = normal.Derivate();

            sturm.Add(nextSturm);
            while (nextSturm.Deg > 0)
            {
                var newSturm = lastSturm.Rest(nextSturm);
                lastSturm = nextSturm;
                nextSturm = newSturm;
                sturm.Add(nextSturm);
            }

            result.AddRange(Shturm(sturm, a, b));
            return(result);
        }
コード例 #7
0
        /// <summary>
        /// Определяет следующие разложения для данного псевдомногочлена по параметру.
        /// </summary>
        /// <returns></returns>
        public void DeterminateNext()
        {
            if (this.Binomial == null)
            {
                this.Binomial    = new int[this.N + 1][];
                this.Binomial[0] = new[] { 1 };
                for (var i = 1; i < this.Binomial.Length; i++)
                {
                    this.Binomial[i]    = new int[i + 1];
                    this.Binomial[i][0] = 1;
                    this.Binomial[i][this.Binomial[i].Length - 1] = 1;
                }

                for (var i = 2; i < this.Binomial.Length; i++)
                {
                    var binomialThis = this.Binomial[i];
                    var binomialPrev = this.Binomial[i - 1];
                    for (var j = 1; j < binomialPrev.Length; j++)
                    {
                        binomialThis[j] = binomialPrev[j - 1] + binomialPrev[j];
                    }
                }
            }

            var x      = new List <int>();
            var y      = new List <double>();
            var points = new List <DataPoint>();

            for (var s = 0; s <= this.N; s++)
            {
                if (this.F[s].Count <= 0)
                {
                    continue;
                }

                x.Add(s);
                y.Add(this.F[s][0].Deg);
                points.Add(new DataPoint(s, this.F[s][0].Deg));
            }

            this.Diagram = new Diagram();

            var begin = 0;

            while (begin < points.Count - 1)
            {
                var end = begin + 1;
                var tan = (y[end] - y[begin]) / (x[end] - x[begin]);
                for (var current = begin + 2; current < points.Count; current++)
                {
                    var newTan = (y[current] - y[begin]) / (x[current] - x[begin]);
                    if (newTan > tan && !Approximation.EqualDoubles(newTan, tan, this.N * this.N))
                    {
                        continue;
                    }

                    end = current;
                    tan = newTan;
                }

                if (-tan <= this.ComponentInSeries.Deg)
                {
                    begin = end;
                    continue;
                }

                var polynomialDeg = x[end] - x[begin];
                var polynomial    = new Polynomial(new double[polynomialDeg + 1])
                {
                    [0]             = this.F[x[begin]][0].K,
                    [polynomialDeg] = this.F[x[end]][0].K
                };

                if (!this.Diagram.MainPoints.Contains(points[begin]))
                {
                    this.Diagram.MainPoints.Add(points[begin]);
                }

                this.Diagram.MainPoints.Add(points[end]);

                for (var current = begin + 1; current < end; current++)
                {
                    var newTan = (y[current] - y[begin]) / (x[current] - x[begin]);
                    if (Approximation.EqualDoubles(newTan, tan, this.N))
                    {
                        polynomial[x[current] - x[begin]] = this.F[x[current]][0].K;
                        this.Diagram.InternalPoints.Add(points[current]);
                    }
                }

                var roots = polynomial.RootsWithSturm();
                foreach (var root in roots)
                {
                    var newComponentInSeries = new Component(-tan, root);
                    var newF = new List <Component> [this.N + 1];
                    for (var s = 0; s <= this.N; s++)
                    {
                        newF[s] = new List <Component>();
                        foreach (var component in this.F[s])
                        {
                            newF[s].Add(new Component(component));
                        }

                        for (var i = 0; i < s; i++)
                        {
                            var temp = newComponentInSeries.Pow(s - i);
                            temp.K *= this.Binomial[s][i];
                            foreach (var component in this.F[s])
                            {
                                newF[i].Add(component.Multiply(temp));
                            }
                        }
                    }

                    foreach (var newFs in newF)
                    {
                        for (var i = 0; i < newFs.Count; i++)
                        {
                            for (var j = i + 1; j < newFs.Count; j++)
                            {
                                if (!Approximation.EqualDoubles(newFs[i].Deg, newFs[j].Deg, this.N * this.N))
                                {
                                    continue;
                                }

                                newFs[i].K += newFs[j].K;
                                newFs.RemoveAt(j);
                                j--;
                            }

                            if (!Approximation.EqualDoubles(newFs[i].K, 0, this.N * this.N))
                            {
                                continue;
                            }

                            newFs.RemoveAt(i);
                            i--;
                        }

                        newFs.Sort();
                    }

                    this.NextF.Add(new Function(newF, newComponentInSeries, this.Binomial));
                }

                begin = end;
            }

            foreach (var point in points)
            {
                if (!this.Diagram.MainPoints.Contains(point) && !this.Diagram.InternalPoints.Contains(point))
                {
                    this.Diagram.UnusedPoints.Add(point);
                }
            }
        }