diff --git a/src/Numerics.Tests/PolynomialTests.cs b/src/Numerics.Tests/PolynomialTests.cs
index ff0ba308..399eb4d7 100644
--- a/src/Numerics.Tests/PolynomialTests.cs
+++ b/src/Numerics.Tests/PolynomialTests.cs
@@ -44,6 +44,7 @@ namespace MathNet.Numerics.UnitTests
[TestFixture, Category("Calculus")]
public class PolynomialTests
{
+
[TestCase(new double[] { 5, 4, 3, 0, 2 }, "5 + 4x + 3x^2 + 2x^4")]
[TestCase(new double[0], "0")]
[TestCase(new double[] { 0, 4, 3, 0, 0 }, "4x + 3x^2")]
@@ -199,6 +200,33 @@ namespace MathNet.Numerics.UnitTests
}
}
+ // 2020-10-07 jbialogrodzki #730 This test focuses particularly on the issue at hand,
+ // i.e. multiplication of zero polynomials, but also attempts to provide more thorough UT
+ // for multiplication in general.
+ [TestCase(new double[] { }, new double[] { }, new double[] { })]
+ [TestCase(new double[] { 0 }, new double[] { }, new double[] { })]
+ [TestCase(new double[] { 1 }, new double[] { }, new double[] { })]
+ [TestCase(new double[] { 1, 2, 3 }, new double[] { }, new double[] { })]
+ [TestCase(new double[] { 0 }, new double[] { 0 }, new double[] { })]
+ [TestCase(new double[] { 1 }, new double[] { 0 }, new double[] { })]
+ [TestCase(new double[] { 1, 2, 3 }, new double[] { 0 }, new double[] { })]
+ [TestCase(new double[] { 2 }, new double[] { 3 }, new double[] { 6 })]
+ [TestCase(new double[] { 2, 3 }, new double[] { 4 }, new double[] { 8, 12 })]
+ [TestCase(new double[] { 2, 3 }, new double[] { 4, 5 }, new double[] { 8, 22, 15 })]
+ public void MultiplyTest2(double[] cLeft, double[] cRight, double[] cExpected)
+ {
+
+ var left = new Polynomial(cLeft);
+ var right = new Polynomial(cRight);
+ var expected = new Polynomial(cExpected);
+
+ var actualLR = left * right;
+ PolynomialTests.TestEqual(actualLR, expected);
+
+ var actualRL = right * left;
+ PolynomialTests.TestEqual(actualRL, expected);
+
+ }
[TestCase(new double[] { 5, 4, 0 }, "5 + 4x")]
[TestCase(new double[] { 0, 0, 0 }, "0")]
@@ -382,5 +410,65 @@ namespace MathNet.Numerics.UnitTests
Assert.AreEqual(p_tar.Coefficients[k], p_res.Coefficients[k], msg);
}
}
+
+ // 2020-10-07 jbialogrodzki #730 This test focuses particularly on the issue at hand,
+ // i.e. evaluating zero polynomials, but also attempts to provide some UT for evaluation
+ // in general (as there has been none). Note the Complex API is tested with real values only.
+ [TestCase(new double[] { }, 0, 0)]
+ [TestCase(new double[] { }, 123, 0)]
+ [TestCase(new double[] { 0 }, 0, 0)]
+ [TestCase(new double[] { 0 }, 123, 0)]
+ [TestCase(new double[] { 1 }, 0, 1)]
+ [TestCase(new double[] { 1 }, 123, 1)]
+ [TestCase(new double[] { 2 }, 0, 2)]
+ [TestCase(new double[] { 2 }, 123, 2)]
+ [TestCase(new double[] { 1, 2 }, 0, 1)]
+ [TestCase(new double[] { 1, 2 }, 3, 7)]
+ [TestCase(new double[] { 1, 2, 3 }, 0, 1)]
+ [TestCase(new double[] { 1, 2, 3 }, 4, 57)]
+ public void EvaluateTest(double[] c, double z, double expected)
+ {
+
+ Complex DoubleToComplex(double value) => new Complex(value, 0);
+
+ var cComplex = c.Select(DoubleToComplex).ToArray();
+ var zComplex = DoubleToComplex(z);
+ var expectedComplex = DoubleToComplex(expected);
+
+ var p = new Polynomial(c);
+
+ // static double Evaluate(double, double[])
+ {
+ var actual = Polynomial.Evaluate(z, c);
+ Assert.AreEqual(expected, actual);
+ }
+
+ // static Complex Evaluate(Complex, double[])
+ {
+ var actual = Polynomial.Evaluate(zComplex, c);
+ Assert.AreEqual(expectedComplex, actual);
+ }
+
+ // static Complex Evaluate(Complex, Complex[])
+ {
+ var actual = Polynomial.Evaluate(zComplex, cComplex);
+ Assert.AreEqual(expectedComplex, actual);
+ }
+
+ // double Evaluate(double)
+ {
+ var actual = p.Evaluate(z);
+ Assert.AreEqual(expected, actual);
+ }
+
+ // Complex Evaluate(Complex)
+ {
+ var actual = p.Evaluate(zComplex);
+ Assert.AreEqual(expectedComplex, actual);
+ }
+
+ }
+
}
+
}
diff --git a/src/Numerics/Polynomial.cs b/src/Numerics/Polynomial.cs
index e551241d..77d8c152 100644
--- a/src/Numerics/Polynomial.cs
+++ b/src/Numerics/Polynomial.cs
@@ -144,16 +144,36 @@ namespace MathNet.Numerics
///
/// The location where to evaluate the polynomial at.
/// The coefficients of the polynomial, coefficient for power k at index k.
+ ///
+ /// is a null reference.
+ ///
public static double Evaluate(double z, params double[] coefficients)
{
- double sum = coefficients[coefficients.Length - 1];
- for (int i = coefficients.Length - 2; i >= 0; --i)
+
+ // 2020-10-07 jbialogrodzki #730 Since this is public API we should probably
+ // handle null arguments? It doesn't seem to have been done consistently in this class though.
+ if (coefficients == null)
+ {
+ throw new ArgumentNullException(nameof(coefficients));
+ }
+
+ // 2020-10-07 jbialogrodzki #730 Zero polynomials need explicit handling.
+ // Without this check, we attempted to peek coefficients at negative indices!
+ int n = coefficients.Length;
+ if (n == 0)
+ {
+ return 0;
+ }
+
+ double sum = coefficients[n - 1];
+ for (int i = n - 2; i >= 0; --i)
{
sum *= z;
sum += coefficients[i];
}
return sum;
+
}
///
@@ -163,16 +183,36 @@ namespace MathNet.Numerics
///
/// The location where to evaluate the polynomial at.
/// The coefficients of the polynomial, coefficient for power k at index k.
+ ///
+ /// is a null reference.
+ ///
public static Complex Evaluate(Complex z, params double[] coefficients)
{
- Complex sum = coefficients[coefficients.Length - 1];
- for (int i = coefficients.Length - 2; i >= 0; --i)
+
+ // 2020-10-07 jbialogrodzki #730 Since this is a public API we should probably
+ // handle null arguments? It doesn't seem to have been done consistently in this class though.
+ if (coefficients == null)
+ {
+ throw new ArgumentNullException(nameof(coefficients));
+ }
+
+ // 2020-10-07 jbialogrodzki #730 Zero polynomials need explicit handling.
+ // Without this check, we attempted to peek coefficients at negative indices!
+ int n = coefficients.Length;
+ if (n == 0)
+ {
+ return 0;
+ }
+
+ Complex sum = coefficients[n - 1];
+ for (int i = n - 2; i >= 0; --i)
{
sum *= z;
sum += coefficients[i];
}
return sum;
+
}
///
@@ -182,16 +222,36 @@ namespace MathNet.Numerics
///
/// The location where to evaluate the polynomial at.
/// The coefficients of the polynomial, coefficient for power k at index k.
+ ///
+ /// is a null reference.
+ ///
public static Complex Evaluate(Complex z, params Complex[] coefficients)
{
- Complex sum = coefficients[coefficients.Length - 1];
- for (int i = coefficients.Length - 2; i >= 0; --i)
+
+ // 2020-10-07 jbialogrodzki #730 Since this is a public API we should probably
+ // handle null arguments? It doesn't seem to have been done consistently in this class though.
+ if (coefficients == null)
+ {
+ throw new ArgumentNullException(nameof(coefficients));
+ }
+
+ // 2020-10-07 jbialogrodzki #730 Zero polynomials need explicit handling.
+ // Without this check, we attempted to peek coefficients at negative indices!
+ int n = coefficients.Length;
+ if (n == 0)
+ {
+ return 0;
+ }
+
+ Complex sum = coefficients[n - 1];
+ for (int i = n - 2; i >= 0; --i)
{
sum *= z;
sum += coefficients[i];
}
return sum;
+
}
///
@@ -480,10 +540,34 @@ namespace MathNet.Numerics
/// Left polynomial
/// Right polynomial
/// Resulting Polynomial
+ ///
+ /// or is a null reference.
+ ///
public static Polynomial Multiply(Polynomial a, Polynomial b)
{
+
+ // 2020-10-07 jbialogrodzki #730 Since this is a public API we should probably
+ // handle null arguments? It doesn't seem to have been done consistently in this class though.
+ if (a == null)
+ {
+ throw new ArgumentNullException(nameof(a));
+ }
+
+ if (b == null)
+ {
+ throw new ArgumentNullException(nameof(b));
+ }
+
var ad = a.Degree;
var bd = b.Degree;
+
+ // 2020-10-07 jbialogrodzki #730 Zero polynomials need explicit handling.
+ // Without this check, we attempted to create arrays of negative lengths!
+ if (ad < 0 || bd < 0)
+ {
+ return Polynomial.Zero;
+ }
+
double[] ac = a.Coefficients;
double[] bc = b.Coefficients;
@@ -499,6 +583,7 @@ namespace MathNet.Numerics
}
return new Polynomial(result);
+
}
///