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); }
/// <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); }
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); }
/// <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); }
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); }
/// <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); }
/// <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); } } }