Created
July 4, 2016 12:26
-
-
Save yuba/155c9e29f0767083dc508b2a98d00e8a to your computer and use it in GitHub Desktop.
n次多項式を表現し、二分法で根を求めることができるクラス。 new Polynomial(-3, -2, 1 , -4, 0, 2).solve() などとやるとdouble配列で根が返ってくる。2次式でも1次式でさえ公式使わず二分法。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.HashSet; | |
import java.util.Set; | |
/** | |
* xの多項式を表します | |
*/ | |
public class Polynomial | |
{ | |
/** | |
* @param a 定数, 1次係数, 2次係数, 3次係数, ... と係数を指定します | |
*/ | |
public Polynomial(double... a) | |
{ | |
if (a == null) throw new NullPointerException(); | |
this.a = a; | |
} | |
/** | |
* xを与えたときの式の値を求めます | |
*/ | |
public double evaluate(double x) | |
{ | |
double result = 0; | |
double xn = 1; | |
for (int i = 0; i < a.length; ++i) | |
{ | |
result += a[i] * xn; | |
xn *= x; | |
} | |
return result; | |
} | |
/** | |
* この多項式の次数を返します。 | |
* @return 定数式の場合は0を返します。 | |
*/ | |
public int getDegree() | |
{ | |
for (int i = a.length - 1; i > 0; --i) | |
{ | |
if (a[i] != 0) return i; | |
} | |
return 0; | |
} | |
/** | |
* この多項式を微分した多項式(導関数)を返します | |
* @return | |
*/ | |
public Polynomial getDerivative() | |
{ | |
int degree = getDegree(); | |
if (degree == 0) return new Polynomial(0); // 定数式の微分は0というやはり定数式 | |
double[] derivative = new double[degree]; | |
for (int i = 1; i <= degree; ++i) | |
{ | |
derivative[i - 1] = a[i] * i; | |
} | |
return new Polynomial(derivative); | |
} | |
public double signum(double x) | |
{ | |
final int degree = getDegree(); | |
if (degree > 0) | |
{ | |
if (x == Double.POSITIVE_INFINITY) return Math.signum(a[degree]); | |
if (x == Double.NEGATIVE_INFINITY) return Math.signum(a[degree]) * ((degree & 1) == 0 ? 1.0 : -1.0); | |
} | |
return Math.signum(evaluate(x)); | |
} | |
public double[] solve() | |
{ | |
if (getDegree() == 0) return new double[0]; | |
return solveInRanges(getDerivative().solve()); | |
} | |
public double[] solveInRanges(double... xs) | |
{ | |
if (xs == null) throw new NullPointerException(); | |
Set<Double> solutions = new HashSet<>(); | |
if (xs.length == 0) | |
{ | |
appendSolutionIfSolved(solutions, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY); | |
} | |
else | |
{ | |
appendSolutionIfSolved(solutions, Double.NEGATIVE_INFINITY, xs[0]); | |
appendSolutionIfSolved(solutions, xs[xs.length - 1], Double.POSITIVE_INFINITY); | |
for (int i = 1; i < xs.length; ++i) | |
{ | |
appendSolutionIfSolved(solutions, xs[i - 1], xs[i]); | |
} | |
} | |
final double[] result = new double[solutions.size()]; | |
int index = 0; | |
for (double d: solutions) result[index++] = d; | |
return result; | |
} | |
private void appendSolutionIfSolved(final Set<Double> solutions, final double l, final double r) | |
{ | |
double lSgn = signum(l), rSgn = signum(r); | |
if (lSgn == 0) solutions.add(l); | |
else if (rSgn == 0) solutions.add(r); | |
else if (lSgn != rSgn) solutions.add(solveInner(l, lSgn, r, rSgn)); | |
} | |
public double solveInRange(double l, double r) | |
{ | |
if (l >= r) throw new IllegalArgumentException("l should less than r"); | |
double lSgn = signum(l), rSgn = signum(r); | |
if (lSgn == 0.0) return l; | |
if (rSgn == 0.0) return r; | |
if (lSgn == rSgn) throw new IllegalArgumentException("l, r are both " + (lSgn == 1.0 ? "positive" : "negative")); | |
return solveInner(l, lSgn, r, rSgn); | |
} | |
private double solveInner(final double l, final double lSgn, final double r, final double rSgn) | |
{ | |
double p = pivot(l, r); | |
if (l == p || p == r) return p; | |
double pSgn = signum(p); | |
if (pSgn == 0.0) return p; | |
if (pSgn == lSgn) return solveInner(p, pSgn, r, rSgn); | |
else return solveInner(l, lSgn, p, pSgn); | |
} | |
private double pivot(final double l, final double r) | |
{ | |
if (l == Double.NEGATIVE_INFINITY) return r > 0 ? 0 : r * 2 - 1; | |
if (r == Double.POSITIVE_INFINITY) return l < 0 ? 0 : l * 2 + 1; | |
return (l + r) / 2; | |
} | |
@Override | |
public String toString() | |
{ | |
final StringBuilder builder = new StringBuilder(); | |
for (int i = a.length - 1; i >= 0; --i) | |
{ | |
if (a[i] != 0) { | |
if (builder.length() > 0) builder.append(" + "); | |
if (i == 0 || a[i] != 1) builder.append(a[i]); | |
if (i > 0) | |
{ | |
builder.append("x"); | |
if (i > 1) builder.append(i); | |
} | |
} | |
} | |
return builder.toString(); | |
} | |
private double[] a; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment