Fixed a rounding bug in the Matrix GetHashCode that would cause matrices that were deemed equal to not have the same hash code

This commit is contained in:
Jeff Moser 2010-04-25 21:50:46 -04:00
parent 592a82b423
commit 9bc97fa1c3
6 changed files with 20 additions and 6 deletions

@ -9,6 +9,10 @@ namespace Moserware.Numerics
/// </summary> /// </summary>
internal class Matrix internal class Matrix
{ {
// Anything smaller than this will be assumed to be rounding error in terms of equality matching
private const int FractionalDigitsToRoundTo = 10;
private static readonly double ErrorTolerance = Math.Pow(0.1, FractionalDigitsToRoundTo); // e.g. 1/10^10
protected double[][] _MatrixRowValues; protected double[][] _MatrixRowValues;
// Note: some properties like Determinant, Inverse, etc are properties instead // Note: some properties like Determinant, Inverse, etc are properties instead
// of methods to make the syntax look nicer even though this sort of goes against // of methods to make the syntax look nicer even though this sort of goes against
@ -387,8 +391,6 @@ namespace Moserware.Numerics
return false; return false;
} }
const double errorTolerance = 0.0000000000001;
for (int currentRow = 0; currentRow < a.Rows; currentRow++) for (int currentRow = 0; currentRow < a.Rows; currentRow++)
{ {
for (int currentColumn = 0; currentColumn < a.Columns; currentColumn++) for (int currentColumn = 0; currentColumn < a.Columns; currentColumn++)
@ -397,7 +399,7 @@ namespace Moserware.Numerics
Math.Abs(a._MatrixRowValues[currentRow][currentColumn] - Math.Abs(a._MatrixRowValues[currentRow][currentColumn] -
b._MatrixRowValues[currentRow][currentColumn]); b._MatrixRowValues[currentRow][currentColumn]);
if (delta > errorTolerance) if (delta > ErrorTolerance)
{ {
return false; return false;
} }
@ -426,7 +428,9 @@ namespace Moserware.Numerics
for (int currentColumn = 0; currentColumn < Columns; currentColumn++) for (int currentColumn = 0; currentColumn < Columns; currentColumn++)
{ {
result += multiplier*_MatrixRowValues[currentRow][currentColumn]; double cellValue = _MatrixRowValues[currentRow][currentColumn];
double roundedValue = Math.Round(cellValue, FractionalDigitsToRoundTo);
result += multiplier*roundedValue;
} }
} }
} }

@ -121,6 +121,16 @@ namespace UnitTests.Numerics
Assert.AreEqual(d, f); Assert.AreEqual(d, f);
Assert.AreEqual(d.GetHashCode(), f.GetHashCode()); Assert.AreEqual(d.GetHashCode(), f.GetHashCode());
// Test rounding (thanks to nsp on GitHub for finding this case)
var g = new SquareMatrix(1, 2.00000000000001,
3, 4);
var h = new SquareMatrix(1, 2,
3, 4);
Assert.IsTrue(g == h);
Assert.AreEqual(g, h);
Assert.AreEqual(g.GetHashCode(), h.GetHashCode());
} }
[Test] [Test]