using System; namespace Amphora.UnitTests { public class RadiansReductionTests : UnitTestSharp.TestFixture { public static readonly double[] FastAngles = { 1.0, 3.0, 7.3, 100.0, 1000.0, 123456.789, 999999.5, 1048575.9999999999, -1.0, -7.3, -1000.0, 1.5707963267948966, 3.141592653589793, 6.283185307179586, }; public static readonly int[] FastQuarters = { 1, 2, 1, 0, 1, 3, 3, 0, 3, 3, 3, 1, 2, 0, }; public static readonly double[] FastHighs = { -0.09084505690810467, -0.022535170724313994, -0.08816891542916408, -0.08450569081046642, -0.09505690810466423, 0.008227603130763641, 0.11351442378982121, 0.05360752722507112, 0.09084505690810467, 0.08816891542916408, 0.09505690810466423, -9.745429581298439e-18, -1.9490859162596877e-17, -3.8981718325193755e-17, }; public static readonly double[] FastLows = { 4.038449470223213e-18, 1.7070075548087973e-18, 2.59686274484631e-18, 1.389100595702082e-18, 1.3218149206362485e-20, 7.362925908488581e-19, 4.26003056734365e-18, 2.57953240010358e-18, -4.038449470223213e-18, -2.59686274484631e-18, -1.3218149206362485e-20, 1.1935507368305006e-34, 2.387101473661001e-34, 4.774202947322002e-34, }; public static readonly double[] LargeAngles = { 1048576.0, 1000000000.0, 1e+22, 1e+100, 1.0715086071862673e+301, 1.7976931348623157e+308, 5.319372648326541e+255, 4503599627370496.0, 123456789012345.6, }; public static readonly int[] LargeQuarters = { 0, 0, 3, 0, 0, 2, 1, 1, 0, }; public static readonly double[] LargeHighs = { 0.05360752724359919, 0.09189533576888376, 0.08763372514362035, -0.06214775215143351, -0.025446009063847114, -0.0007897228727469473, 7.459856259370163e-20, 0.08068755952925184, -0.0076511798557268714, }; public static readonly double[] LargeLows = { 1.5922696001027692e-18, 6.495213323122195e-18, -2.778882058704996e-18, -3.3990966066839534e-18, -1.594826779104657e-18, 2.976105643256818e-20, -6.010223258436573e-36, -2.4142528224256724e-18, 3.6367939211294946e-19, }; public static bool PairIsWithinOfTheExpectedPair(double high, double low, double expectedHigh, double expectedLow, double relativeTolerance) { return Math.Abs((high - expectedHigh) + (low - expectedLow)) <= Math.Abs(expectedHigh) * relativeTolerance; } public class ReduceTests : UnitTestSharp.TestFixture { public void ReferenceAngles_GiveTheNearestQuarterAndWhatIsLeft() { for (int i = 0; i < FastAngles.Length; i++) { double high; double low; int quarter = RadiansReduction.Reduce(FastAngles[i], out high, out low); CheckEqual(FastQuarters[i], quarter); CheckTrue(PairIsWithinOfTheExpectedPair(high, low, FastHighs[i], FastLows[i], 1e-26)); } } public void WhatIsLeft_IsWithinAnEighthOfATurn() { for (int i = 0; i < FastAngles.Length; i++) { double high; double low; RadiansReduction.Reduce(FastAngles[i], out high, out low); CheckLess(Math.Abs(high), 0.125000000000001); } } public void LowPart_IsUnderAnUlpOfTheHighPart() { for (int i = 0; i < FastAngles.Length; i++) { double high; double low; RadiansReduction.Reduce(FastAngles[i], out high, out low); CheckLess(Math.Abs(low), Math.Abs(high) * 1.2e-16); } } } public class ReduceLargeTests : UnitTestSharp.TestFixture { public void ReferenceAngles_GiveTheNearestQuarterAndWhatIsLeft() { for (int i = 0; i < LargeAngles.Length; i++) { double high; double low; int quarter = RadiansReduction.ReduceLarge(LargeAngles[i], out high, out low); CheckEqual(LargeQuarters[i], quarter); CheckTrue(PairIsWithinOfTheExpectedPair(high, low, LargeHighs[i], LargeLows[i], 1e-30)); } } public void AnglesTheFastReductionTakes_GiveTheSameAnswer() { for (int i = 0; i < FastAngles.Length; i++) { double fastHigh; double fastLow; double largeHigh; double largeLow; double angle = Math.Abs(FastAngles[i]); int fastQuarter = RadiansReduction.Reduce(angle, out fastHigh, out fastLow); int largeQuarter = RadiansReduction.ReduceLarge(angle, out largeHigh, out largeLow); CheckEqual(fastQuarter, largeQuarter); CheckTrue(PairIsWithinOfTheExpectedPair(fastHigh, fastLow, largeHigh, largeLow, 1e-26)); } } public void WhatIsLeft_IsWithinAnEighthOfATurn() { for (int i = 0; i < LargeAngles.Length; i++) { double high; double low; RadiansReduction.ReduceLarge(LargeAngles[i], out high, out low); CheckLess(Math.Abs(high), 0.125000000000001); } } } } }