Added more unit tests to the floating point helper classes; Variegator unit test is now internal

git-svn-id: file:///srv/devel/repo-conversion/nusu@287 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
Markus Ewald 2013-07-15 13:38:21 +00:00
parent 2462dd6dc4
commit 63ddef021d
7 changed files with 92 additions and 10 deletions

View File

@ -188,7 +188,7 @@
</Compile> </Compile>
<Compile Include="Source\Collections\Variegator.cs" /> <Compile Include="Source\Collections\Variegator.cs" />
<Compile Include="Source\Collections\Variegator.Test.cs"> <Compile Include="Source\Collections\Variegator.Test.cs">
<DependentUpon>TransformingReadOnlyCollection.cs</DependentUpon> <DependentUpon>Variegator.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="Source\Collections\WeakCollection.cs" /> <Compile Include="Source\Collections\WeakCollection.cs" />
<Compile Include="Source\Collections\WeakCollection.Interfaces.cs"> <Compile Include="Source\Collections\WeakCollection.Interfaces.cs">

View File

@ -217,6 +217,10 @@
<Compile Include="Source\Collections\TransformingReadOnlyCollection.Test.cs"> <Compile Include="Source\Collections\TransformingReadOnlyCollection.Test.cs">
<DependentUpon>TransformingReadOnlyCollection.cs</DependentUpon> <DependentUpon>TransformingReadOnlyCollection.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="Source\Collections\Variegator.cs" />
<Compile Include="Source\Collections\Variegator.Test.cs">
<DependentUpon>Variegator.cs</DependentUpon>
</Compile>
<Compile Include="Source\Collections\WeakCollection.cs" /> <Compile Include="Source\Collections\WeakCollection.cs" />
<Compile Include="Source\Collections\WeakCollection.Interfaces.cs"> <Compile Include="Source\Collections\WeakCollection.Interfaces.cs">
<DependentUpon>WeakCollection.cs</DependentUpon> <DependentUpon>WeakCollection.cs</DependentUpon>

View File

@ -228,6 +228,10 @@
<Compile Include="Source\Collections\TransformingReadOnlyCollection.Test.cs"> <Compile Include="Source\Collections\TransformingReadOnlyCollection.Test.cs">
<DependentUpon>TransformingReadOnlyCollection.cs</DependentUpon> <DependentUpon>TransformingReadOnlyCollection.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="Source\Collections\Variegator.cs" />
<Compile Include="Source\Collections\Variegator.Test.cs">
<DependentUpon>Variegator.cs</DependentUpon>
</Compile>
<Compile Include="Source\Collections\WeakCollection.cs" /> <Compile Include="Source\Collections\WeakCollection.cs" />
<Compile Include="Source\Collections\WeakCollection.Interfaces.cs"> <Compile Include="Source\Collections\WeakCollection.Interfaces.cs">
<DependentUpon>WeakCollection.cs</DependentUpon> <DependentUpon>WeakCollection.cs</DependentUpon>

View File

@ -29,7 +29,7 @@ namespace Nuclex.Support.Collections {
/// <summary>Unit Test for the Variegator multi dictionary</summary> /// <summary>Unit Test for the Variegator multi dictionary</summary>
[TestFixture] [TestFixture]
public class VariegatorTest { internal class VariegatorTest {
/// <summary> /// <summary>
/// Tests whether the default constructor of the reverse comparer works /// Tests whether the default constructor of the reverse comparer works

View File

@ -20,7 +20,6 @@ License along with this library
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
namespace Nuclex.Support.Collections { namespace Nuclex.Support.Collections {

View File

@ -29,11 +29,11 @@ namespace Nuclex.Support {
/// <summary>Unit Test for the FloatHelper class</summary> /// <summary>Unit Test for the FloatHelper class</summary>
[TestFixture] [TestFixture]
internal class FloatHelperTest { public class FloatHelperTest {
/// <summary>Tests the floating point value comparison helper</summary> /// <summary>Tests the floating point value comparison helper</summary>
[Test] [Test]
public void TestFloatComparison() { public void UlpDistancesOnFloatsCompareAsEqual() {
Assert.IsTrue( Assert.IsTrue(
FloatHelper.AreAlmostEqual(0.00000001f, 0.0000000100000008f, 1), FloatHelper.AreAlmostEqual(0.00000001f, 0.0000000100000008f, 1),
"Minimal difference between very small floating point numbers is considered equal" "Minimal difference between very small floating point numbers is considered equal"
@ -55,7 +55,7 @@ namespace Nuclex.Support {
/// <summary>Tests the double precision floating point value comparison helper</summary> /// <summary>Tests the double precision floating point value comparison helper</summary>
[Test] [Test]
public void TestDoubleComparison() { public void UlpDistancesOnDoublesCompareAsEqual() {
Assert.IsTrue( Assert.IsTrue(
FloatHelper.AreAlmostEqual(0.00000001, 0.000000010000000000000002, 1), FloatHelper.AreAlmostEqual(0.00000001, 0.000000010000000000000002, 1),
"Minimal difference between very small double precision floating point " + "Minimal difference between very small double precision floating point " +
@ -81,7 +81,7 @@ namespace Nuclex.Support {
/// <summary>Tests the integer reinterpretation functions</summary> /// <summary>Tests the integer reinterpretation functions</summary>
[Test] [Test]
public void TestIntegerReinterpretation() { public void IntegersCanBeReinterpretedAsFloats() {
Assert.AreEqual( Assert.AreEqual(
12345.0f, 12345.0f,
FloatHelper.ReinterpretAsFloat(FloatHelper.ReinterpretAsInt(12345.0f)), FloatHelper.ReinterpretAsFloat(FloatHelper.ReinterpretAsInt(12345.0f)),
@ -91,7 +91,7 @@ namespace Nuclex.Support {
/// <summary>Tests the long reinterpretation functions</summary> /// <summary>Tests the long reinterpretation functions</summary>
[Test] [Test]
public void TestLongReinterpretation() { public void LongsCanBeReinterpretedAsDoubles() {
Assert.AreEqual( Assert.AreEqual(
12345.67890, 12345.67890,
FloatHelper.ReinterpretAsDouble(FloatHelper.ReinterpretAsLong(12345.67890)), FloatHelper.ReinterpretAsDouble(FloatHelper.ReinterpretAsLong(12345.67890)),
@ -101,7 +101,7 @@ namespace Nuclex.Support {
/// <summary>Tests the floating point reinterpretation functions</summary> /// <summary>Tests the floating point reinterpretation functions</summary>
[Test] [Test]
public void TestFloatReinterpretation() { public void FloatsCanBeReinterpretedAsIntegers() {
Assert.AreEqual( Assert.AreEqual(
12345, 12345,
FloatHelper.ReinterpretAsInt(FloatHelper.ReinterpretAsFloat(12345)), FloatHelper.ReinterpretAsInt(FloatHelper.ReinterpretAsFloat(12345)),
@ -109,12 +109,33 @@ namespace Nuclex.Support {
); );
} }
/// <summary>
/// Verifies that the IsZero() method can distinguish zero from very small values
/// </summary>
[Test]
public void CanDetermineIfFloatIsZero() {
Assert.IsTrue(FloatHelper.IsZero(FloatHelper.PositiveZeroFloat));
Assert.IsTrue(FloatHelper.IsZero(FloatHelper.NegativeZeroFloat));
Assert.IsFalse(FloatHelper.IsZero(1.401298E-45f));
Assert.IsFalse(FloatHelper.IsZero(-1.401298E-45f));
}
/// <summary>
/// Verifies that the IsZero() method can distinguish zero from very small values
/// </summary>
[Test]
public void CanDetermineIfDoubleIsZero() {
Assert.IsTrue(FloatHelper.IsZero(FloatHelper.PositiveZeroDouble));
Assert.IsTrue(FloatHelper.IsZero(FloatHelper.NegativeZeroDouble));
Assert.IsFalse(FloatHelper.IsZero(4.94065645841247E-324));
Assert.IsFalse(FloatHelper.IsZero(-4.94065645841247E-324));
}
/// <summary> /// <summary>
/// Tests the double prevision floating point reinterpretation functions /// Tests the double prevision floating point reinterpretation functions
/// </summary> /// </summary>
[Test] [Test]
public void TestDoubleReinterpretation() { public void DoublesCanBeReinterpretedAsLongs() {
Assert.AreEqual( Assert.AreEqual(
1234567890, 1234567890,
FloatHelper.ReinterpretAsLong(FloatHelper.ReinterpretAsDouble(1234567890)), FloatHelper.ReinterpretAsLong(FloatHelper.ReinterpretAsDouble(1234567890)),
@ -122,6 +143,26 @@ namespace Nuclex.Support {
); );
} }
// http://www.altdevblogaday.com/2012/02/22/comparing-floating-point-numbers-2012-edition/
// Make both positive
// If both are negative -> fine
// If both are positive -> fine
// If different -> Measure both distances to zero in ulps and sum them
public void NegativeZeroEqualsPositiveZero() {
float zero = 0.0f;
float zeroPlusOneUlp = FloatHelper.ReinterpretAsFloat(
FloatHelper.ReinterpretAsInt(zero) + 1
);
float zeroMinusOneUlp = -zeroPlusOneUlp;
bool test = FloatHelper.AreAlmostEqual(zeroMinusOneUlp, zeroPlusOneUlp, 1);
Assert.IsFalse(FloatHelper.AreAlmostEqual(zero, zeroPlusOneUlp, 0));
Assert.IsTrue(FloatHelper.AreAlmostEqual(zero, zeroPlusOneUlp, 1));
Assert.IsFalse(FloatHelper.AreAlmostEqual(zero, zeroMinusOneUlp, 0));
Assert.IsTrue(FloatHelper.AreAlmostEqual(zero, zeroMinusOneUlp, 1));
}
} }
} // namespace Nuclex.Support } // namespace Nuclex.Support

View File

@ -88,6 +88,40 @@ namespace Nuclex.Support {
#endregion // struct DoubleLongUnion #endregion // struct DoubleLongUnion
/// <summary>A floating point value that holds a positive zero</summary>
public const float PositiveZeroFloat = +0.0f;
/// <summary>A floating point value that holds a negative zero</summary>
/// <remarks>
/// Negative zeros have a special representation in IEEE 752 floating point math
/// </remarks>
public const float NegativeZeroFloat = -0.0f;
/// <summary>A double precision floating point value that holds a positive zero</summary>
public const double PositiveZeroDouble = +0.0;
/// <summary>A doublep precision floating point value that holds a negative zero</summary>
/// <remarks>
/// Negative zeros have a special representation in IEEE 752 floating point math
/// </remarks>
public const double NegativeZeroDouble = -0.0;
/// <summary>Checks whether the floating point value is exactly zero</summary>
/// <param name="value">Value that will be checked for being zero</param>
/// <returns>True if the value is zero, false otherwise</returns>
public static bool IsZero(float value) {
return (value == PositiveZeroFloat) || (value == NegativeZeroFloat);
}
/// <summary>
/// Checks whether the double precision floating point value is exactly zero
/// </summary>
/// <param name="value">Value that will be checked for being zero</param>
/// <returns>True if the value is zero, false otherwise</returns>
public static bool IsZero(double value) {
return (value == PositiveZeroDouble) || (value == NegativeZeroDouble);
}
/// <summary>Compares two floating point values for equality</summary> /// <summary>Compares two floating point values for equality</summary>
/// <param name="left">First floating point value to be compared</param> /// <param name="left">First floating point value to be compared</param>
/// <param name="right">Second floating point value t be compared</param> /// <param name="right">Second floating point value t be compared</param>