//[Fact] public void Atan2Benchmark() { var deltas = new List <decimal>(); var swf = new Stopwatch(); var swd = new Stopwatch(); foreach (var y in m_testCases) { foreach (var x in m_testCases) { for (int k = 0; k < 1000; ++k) { var yf = (Fix64)y; var xf = (Fix64)x; swf.Start(); var actualF = MathFix.Atan2(yf, xf); swf.Stop(); swd.Start(); var expected = Math.Atan2((double)yf, (double)xf); swd.Stop(); deltas.Add(Math.Abs((decimal)actualF - (decimal)expected)); } } } Console.WriteLine("Max error: {0} ({1} times precision)", deltas.Max(), deltas.Max() / Fix64.Precision); Console.WriteLine("Average precision: {0} ({1} times precision)", deltas.Average(), deltas.Average() / Fix64.Precision); Console.WriteLine("Fix64.Atan2 time = {0}ms, Math.Atan2 time = {1}ms", swf.ElapsedMilliseconds, swd.ElapsedMilliseconds); }
public void Atan() { var maxDelta = 0.00000001m; var deltas = new List <decimal>(); Assert.Equal(Fix64.Zero, MathFix.Atan(Fix64.Zero)); // Precision for (var x = -1.0; x < 1.0; x += 0.0001) { var xf = (Fix64)x; var actual = (decimal)MathFix.Atan(xf); var expected = (decimal)Math.Atan((double)xf); var delta = Math.Abs(actual - expected); deltas.Add(delta); Assert.True(delta <= maxDelta, string.Format("Precision: Atan({0}): expected {1} but got {2}", xf, expected, actual)); } // Scalability and edge cases foreach (var x in m_testCases) { var xf = (Fix64)x; var actual = (decimal)MathFix.Atan(xf); var expected = (decimal)Math.Atan((double)xf); var delta = Math.Abs(actual - expected); deltas.Add(delta); Assert.True(delta <= maxDelta, string.Format("Scalability: Atan({0}): expected {1} but got {2}", xf, expected, actual)); } Console.WriteLine("Max error: {0} ({1} times precision)", deltas.Max(), deltas.Max() / Fix64.Precision); Console.WriteLine("Average precision: {0} ({1} times precision)", deltas.Average(), deltas.Average() / Fix64.Precision); }
public void Pow() { for (int i = 0; i < m_testCases.Length; ++i) { var b = Fix64.FromRaw(m_testCases[i]); for (int j = 0; j < m_testCases.Length; ++j) { var e = Fix64.FromRaw(m_testCases[j]); if (b == Fix64.Zero && e < Fix64.Zero) { Assert.Throws <DivideByZeroException>(() => MathFix.Pow(b, e)); } else if (b < Fix64.Zero && e != Fix64.Zero) { Assert.Throws <ArgumentOutOfRangeException>(() => MathFix.Pow(b, e)); } else { var expected = e == Fix64.Zero ? 1 : b == Fix64.Zero ? 0 : Math.Min(Math.Pow((double)b, (double)e), (double)Fix64.MaxValue); // Absolute precision deteriorates with large result values, take this into account // Similarly, large exponents reduce precision, even if result is small. double maxDelta = Math.Abs((double)e) > 100000000 ? 0.5 : expected > 100000000 ? 10 : expected > 1000 ? 0.5 : 0.00001; var actual = (double)MathFix.Pow(b, e); var delta = Math.Abs(expected - actual); Assert.True(delta <= maxDelta, string.Format("Pow({0}, {1}) = expected {2} but got {3}", b, e, expected, actual)); } } } }
public void Tan() { Assert.True(MathFix.Tan(Fix64.Zero) == Fix64.Zero); Assert.True(MathFix.Tan(MathFix.PI) == Fix64.Zero); Assert.True(MathFix.Tan(-MathFix.PI) == Fix64.Zero); Assert.True(MathFix.Tan(MathFix.PIOver2 - (Fix64)0.001) > Fix64.Zero); Assert.True(MathFix.Tan(MathFix.PIOver2 + (Fix64)0.001) < Fix64.Zero); Assert.True(MathFix.Tan(-MathFix.PIOver2 - (Fix64)0.001) > Fix64.Zero); Assert.True(MathFix.Tan(-MathFix.PIOver2 + (Fix64)0.001) < Fix64.Zero); for (double angle = 0; /*-2 * Math.PI;*/ angle <= 2 * Math.PI; angle += 0.0001) { var f = (Fix64)angle; var actualF = MathFix.Tan(f); var expected = (decimal)Math.Tan(angle); Assert.Equal(actualF > Fix64.Zero, expected > 0); //TODO figure out a real way to test this function } //foreach (var val in m_testCases) { // var f = (Fix64)val; // var actualF = Fix64.Tan(f); // var expected = (decimal)Math.Tan((double)f); // var delta = Math.Abs(expected - (decimal)actualF); // Assert.True(delta <= 0.01, string.Format("Tan({0}): expected {1} but got {2}", f, expected, actualF)); //} }
public void Cos() { Assert.True(MathFix.Cos(Fix64.Zero) == Fix64.One); Assert.True(MathFix.Cos(MathFix.PIOver2) == Fix64.Zero); Assert.True(MathFix.Cos(MathFix.PI) == -Fix64.One); Assert.True(MathFix.Cos(MathFix.PI + MathFix.PIOver2) == Fix64.Zero); Assert.True(MathFix.Cos(MathFix.PITimes2) == Fix64.One); Assert.True(MathFix.Cos(-MathFix.PIOver2) == -Fix64.Zero); Assert.True(MathFix.Cos(-MathFix.PI) == -Fix64.One); Assert.True(MathFix.Cos(-MathFix.PI - MathFix.PIOver2) == Fix64.Zero); Assert.True(MathFix.Cos(-MathFix.PITimes2) == Fix64.One); for (double angle = -2 * Math.PI; angle <= 2 * Math.PI; angle += 0.0001) { var f = (Fix64)angle; var actualF = MathFix.Cos(f); var expected = (decimal)Math.Cos(angle); var delta = Math.Abs(expected - (decimal)actualF); Assert.True(delta <= 3 * Fix64.Precision, string.Format("Cos({0}): expected {1} but got {2}", angle, expected, actualF)); } foreach (var val in m_testCases) { var f = Fix64.FromRaw(val); var actualF = MathFix.Cos(f); var expected = (decimal)Math.Cos((double)f); var delta = Math.Abs(expected - (decimal)actualF); Assert.True(delta <= 0.0000001M, string.Format("Cos({0}): expected {1} but got {2}", f, expected, actualF)); } }
public void Floor() { var sources = new[] { -5.1m, -1, 0, 1, 5.1m }; var expecteds = new[] { -6m, -1, 0, 1, 5m }; for (int i = 0; i < sources.Length; ++i) { var actual = (decimal)MathFix.Floor((Fix64)sources[i]); var expected = expecteds[i]; Assert.Equal(expected, actual); } }
public void Sign() { var sources = new[] { Fix64.MinValue, (Fix64)(-1), Fix64.Zero, Fix64.One, Fix64.MaxValue }; var expecteds = new[] { -1, -1, 0, 1, 1 }; for (int i = 0; i < sources.Length; ++i) { var actual = MathFix.Sign(sources[i]); var expected = expecteds[i]; Assert.Equal(expected, actual); } }
public void Round() { var sources = new[] { -5.5m, -5.1m, -4.5m, -4.4m, -1, 0, 1, 4.5m, 4.6m, 5.4m, 5.5m }; var expecteds = new[] { -6m, -5m, -4m, -4m, -1, 0, 1, 4m, 5m, 5m, 6m }; for (int i = 0; i < sources.Length; ++i) { var actual = (decimal)MathFix.Round((Fix64)sources[i]); var expected = expecteds[i]; Assert.Equal(expected, actual); } Assert.Equal(Fix64.MaxValue, MathFix.Round(Fix64.MaxValue)); }
public void FastAbs() { Assert.Equal(Fix64.MinValue, MathFix.FastAbs(Fix64.MinValue)); var sources = new[] { -1, 0, 1, int.MaxValue }; var expecteds = new[] { 1, 0, 1, int.MaxValue }; for (int i = 0; i < sources.Length; ++i) { var actual = MathFix.FastAbs((Fix64)sources[i]); var expected = (Fix64)expecteds[i]; Assert.Equal(expected, actual); } }
public void Ceiling() { var sources = new[] { -5.1m, -1, 0, 1, 5.1m }; var expecteds = new[] { -5m, -1, 0, 1, 6m }; for (int i = 0; i < sources.Length; ++i) { var actual = (decimal)MathFix.Ceiling((Fix64)sources[i]); var expected = expecteds[i]; Assert.Equal(expected, actual); } Assert.Equal(Fix64.MaxValue, MathFix.Ceiling(Fix64.MaxValue)); }
public void Pow2() { double maxDelta = 0.0000001; for (int i = 0; i < m_testCases.Length; ++i) { var e = Fix64.FromRaw(m_testCases[i]); var expected = Math.Min(Math.Pow(2, (double)e), (double)Fix64.MaxValue); var actual = (double)MathFix.Pow2(e); var delta = Math.Abs(expected - actual); Assert.True(delta <= maxDelta, string.Format("Pow2({0}) = expected {1} but got {2}", e, expected, actual)); } }
public void Sqrt() { for (int i = 0; i < m_testCases.Length; ++i) { var f = Fix64.FromRaw(m_testCases[i]); if (MathFix.Sign(f) < 0) { Assert.Throws <ArgumentOutOfRangeException>(() => MathFix.Sqrt(f)); } else { var expected = Math.Sqrt((double)f); var actual = (double)MathFix.Sqrt(f); var delta = (decimal)Math.Abs(expected - actual); Assert.True(delta <= Fix64.Precision); } } }
public void Atan2() { var deltas = new List <decimal>(); // Identities Assert.Equal(MathFix.Atan2(Fix64.Zero, -Fix64.One), MathFix.PI); Assert.Equal(MathFix.Atan2(Fix64.Zero, Fix64.Zero), Fix64.Zero); Assert.Equal(MathFix.Atan2(Fix64.Zero, Fix64.One), Fix64.Zero); Assert.Equal(MathFix.Atan2(Fix64.One, Fix64.Zero), MathFix.PIOver2); Assert.Equal(MathFix.Atan2(-Fix64.One, Fix64.Zero), -MathFix.PIOver2); // Precision for (var y = -1.0; y < 1.0; y += 0.01) { for (var x = -1.0; x < 1.0; x += 0.01) { var yf = (Fix64)y; var xf = (Fix64)x; var actual = MathFix.Atan2(yf, xf); var expected = (decimal)Math.Atan2((double)yf, (double)xf); var delta = Math.Abs((decimal)actual - expected); deltas.Add(delta); Assert.True(delta <= 0.005M, string.Format("Precision: Atan2({0}, {1}): expected {2} but got {3}", yf, xf, expected, actual)); } } // Scalability and edge cases foreach (var y in m_testCases) { foreach (var x in m_testCases) { var yf = (Fix64)y; var xf = (Fix64)x; var actual = (decimal)MathFix.Atan2(yf, xf); var expected = (decimal)Math.Atan2((double)yf, (double)xf); var delta = Math.Abs(actual - expected); deltas.Add(delta); Assert.True(delta <= 0.005M, string.Format("Scalability: Atan2({0}, {1}): expected {2} but got {3}", yf, xf, expected, actual)); } } Console.WriteLine("Max error: {0} ({1} times precision)", deltas.Max(), deltas.Max() / Fix64.Precision); Console.WriteLine("Average precision: {0} ({1} times precision)", deltas.Average(), deltas.Average() / Fix64.Precision); }
public void FastCos() { for (double angle = -2 * Math.PI; angle <= 2 * Math.PI; angle += 0.0001) { var f = (Fix64)angle; var actualF = MathFix.FastCos(f); var expected = (decimal)Math.Cos(angle); var delta = Math.Abs(expected - (decimal)actualF); Assert.True(delta <= 50000 * Fix64.Precision, string.Format("Cos({0}): expected {1} but got {2}", angle, expected, actualF)); } foreach (var val in m_testCases) { var f = Fix64.FromRaw(val); var actualF = MathFix.FastCos(f); var expected = (decimal)Math.Cos((double)f); var delta = Math.Abs(expected - (decimal)actualF); Assert.True(delta <= 0.01M, string.Format("Cos({0}): expected {1} but got {2}", f, expected, actualF)); } }
public void Acos() { var maxDelta = 0.00000001m; var deltas = new List <decimal>(); Assert.Equal(Fix64.Zero, MathFix.Acos(Fix64.One)); Assert.Equal(MathFix.PIOver2, MathFix.Acos(Fix64.Zero)); Assert.Equal(MathFix.PI, MathFix.Acos(-Fix64.One)); // Precision for (var x = -1.0; x < 1.0; x += 0.001) { var xf = (Fix64)x; var actual = (decimal)MathFix.Acos(xf); var expected = (decimal)Math.Acos((double)xf); var delta = Math.Abs(actual - expected); deltas.Add(delta); Assert.True(delta <= maxDelta, string.Format("Precision: Acos({0}): expected {1} but got {2}", xf, expected, actual)); } for (int i = 0; i < m_testCases.Length; ++i) { var b = Fix64.FromRaw(m_testCases[i]); if (b < -Fix64.One || b > Fix64.One) { Assert.Throws <ArgumentOutOfRangeException>(() => MathFix.Acos(b)); } else { var expected = (decimal)Math.Acos((double)b); var actual = (decimal)MathFix.Acos(b); var delta = Math.Abs(expected - actual); deltas.Add(delta); Assert.True(delta <= maxDelta, string.Format("Acos({0}) = expected {1} but got {2}", b, expected, actual)); } } Console.WriteLine("Max error: {0} ({1} times precision)", deltas.Max(), deltas.Max() / Fix64.Precision); Console.WriteLine("Average precision: {0} ({1} times precision)", deltas.Average(), deltas.Average() / Fix64.Precision); }
public void Ln() { double maxDelta = 0.00000001; for (int j = 0; j < m_testCases.Length; ++j) { var b = Fix64.FromRaw(m_testCases[j]); if (b <= Fix64.Zero) { Assert.Throws <ArgumentOutOfRangeException>(() => MathFix.Log(b)); } else { var expected = Math.Log((double)b); var actual = (double)MathFix.Log(b); var delta = Math.Abs(expected - actual); Assert.True(delta <= maxDelta, string.Format("Ln({0}) = expected {1} but got {2}", b, expected, actual)); } } }