blob: 9a5a1182e1145d74d7c20598b4b8242af0f2fb92 [file] [log] [blame]
using NUnit.Framework;
using RandomizedTesting.Generators;
using System;
using Assert = Lucene.Net.TestFramework.Assert;
namespace Lucene.Net.Util
{
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
[TestFixture]
public class TestSloppyMath : LuceneTestCase
{
// accuracy for cos()
internal static double COS_DELTA = 1E-15;
// accuracy for asin()
internal static double ASIN_DELTA = 1E-7;
[Test]
public virtual void TestCos()
{
Assert.IsTrue(double.IsNaN(Math.Cos(double.NaN)));
Assert.IsTrue(double.IsNaN(Math.Cos(double.NegativeInfinity)));
Assert.IsTrue(double.IsNaN(Math.Cos(double.PositiveInfinity)));
Assert.AreEqual(Math.Cos(1), Math.Cos(1), COS_DELTA);
Assert.AreEqual(Math.Cos(0), Math.Cos(0), COS_DELTA);
Assert.AreEqual(Math.Cos(Math.PI / 2), Math.Cos(Math.PI / 2), COS_DELTA);
Assert.AreEqual(Math.Cos(-Math.PI / 2), Math.Cos(-Math.PI / 2), COS_DELTA);
Assert.AreEqual(Math.Cos(Math.PI / 4), Math.Cos(Math.PI / 4), COS_DELTA);
Assert.AreEqual(Math.Cos(-Math.PI / 4), Math.Cos(-Math.PI / 4), COS_DELTA);
Assert.AreEqual(Math.Cos(Math.PI * 2 / 3), Math.Cos(Math.PI * 2 / 3), COS_DELTA);
Assert.AreEqual(Math.Cos(-Math.PI * 2 / 3), Math.Cos(-Math.PI * 2 / 3), COS_DELTA);
Assert.AreEqual(Math.Cos(Math.PI / 6), Math.Cos(Math.PI / 6), COS_DELTA);
Assert.AreEqual(Math.Cos(-Math.PI / 6), Math.Cos(-Math.PI / 6), COS_DELTA);
// testing purely random longs is inefficent, as for stupid parameters we just
// pass thru to Math.cos() instead of doing some huperduper arg reduction
for (int i = 0; i < 10000; i++)
{
double d = Random.NextDouble() * SloppyMath.SIN_COS_MAX_VALUE_FOR_INT_MODULO;
if (Random.NextBoolean())
{
d = -d;
}
Assert.AreEqual(Math.Cos(d), Math.Cos(d), COS_DELTA);
}
}
[Test]
public virtual void TestAsin()
{
Assert.IsTrue(double.IsNaN(Math.Asin(double.NaN)));
Assert.IsTrue(double.IsNaN(Math.Asin(2)));
Assert.IsTrue(double.IsNaN(Math.Asin(-2)));
Assert.AreEqual(-Math.PI / 2, Math.Asin(-1), ASIN_DELTA);
Assert.AreEqual(-Math.PI / 3, Math.Asin(-0.8660254), ASIN_DELTA);
Assert.AreEqual(-Math.PI / 4, Math.Asin(-0.7071068), ASIN_DELTA);
Assert.AreEqual(-Math.PI / 6, Math.Asin(-0.5), ASIN_DELTA);
Assert.AreEqual(0, Math.Asin(0), ASIN_DELTA);
Assert.AreEqual(Math.PI / 6, Math.Asin(0.5), ASIN_DELTA);
Assert.AreEqual(Math.PI / 4, Math.Asin(0.7071068), ASIN_DELTA);
Assert.AreEqual(Math.PI / 3, Math.Asin(0.8660254), ASIN_DELTA);
Assert.AreEqual(Math.PI / 2, Math.Asin(1), ASIN_DELTA);
// only values -1..1 are useful
for (int i = 0; i < 10000; i++)
{
double d = Random.NextDouble();
if (Random.NextBoolean())
{
d = -d;
}
Assert.AreEqual(Math.Asin(d), Math.Asin(d), ASIN_DELTA);
Assert.IsTrue(Math.Asin(d) >= -Math.PI / 2);
Assert.IsTrue(Math.Asin(d) <= Math.PI / 2);
}
}
[Test]
public virtual void TestHaversin()
{
Assert.IsTrue(double.IsNaN(SloppyMath.Haversin(1, 1, 1, double.NaN)));
Assert.IsTrue(double.IsNaN(SloppyMath.Haversin(1, 1, double.NaN, 1)));
Assert.IsTrue(double.IsNaN(SloppyMath.Haversin(1, double.NaN, 1, 1)));
Assert.IsTrue(double.IsNaN(SloppyMath.Haversin(double.NaN, 1, 1, 1)));
Assert.AreEqual(0, SloppyMath.Haversin(0, 0, 0, 0), 0D);
Assert.AreEqual(0, SloppyMath.Haversin(0, -180, 0, -180), 0D);
Assert.AreEqual(0, SloppyMath.Haversin(0, -180, 0, 180), 0D);
Assert.AreEqual(0, SloppyMath.Haversin(0, 180, 0, 180), 0D);
Assert.AreEqual(0, SloppyMath.Haversin(90, 0, 90, 0), 0D);
Assert.AreEqual(0, SloppyMath.Haversin(90, -180, 90, -180), 0D);
Assert.AreEqual(0, SloppyMath.Haversin(90, -180, 90, 180), 0D);
Assert.AreEqual(0, SloppyMath.Haversin(90, 180, 90, 180), 0D);
// Test half a circle on the equator, using WGS84 earth radius
double earthRadiusKMs = 6378.137;
double halfCircle = earthRadiusKMs * Math.PI;
Assert.AreEqual(halfCircle, SloppyMath.Haversin(0, 0, 0, 180), 0D);
Random r = Random;
double randomLat1 = 40.7143528 + (r.Next(10) - 5) * 360;
double randomLon1 = -74.0059731 + (r.Next(10) - 5) * 360;
double randomLat2 = 40.65 + (r.Next(10) - 5) * 360;
double randomLon2 = -73.95 + (r.Next(10) - 5) * 360;
Assert.AreEqual(8.572, SloppyMath.Haversin(randomLat1, randomLon1, randomLat2, randomLon2), 0.01D);
// from solr and ES tests (with their respective epsilons)
Assert.AreEqual(0, SloppyMath.Haversin(40.7143528, -74.0059731, 40.7143528, -74.0059731), 0D);
Assert.AreEqual(5.286, SloppyMath.Haversin(40.7143528, -74.0059731, 40.759011, -73.9844722), 0.01D);
Assert.AreEqual(0.4621, SloppyMath.Haversin(40.7143528, -74.0059731, 40.718266, -74.007819), 0.01D);
Assert.AreEqual(1.055, SloppyMath.Haversin(40.7143528, -74.0059731, 40.7051157, -74.0088305), 0.01D);
Assert.AreEqual(1.258, SloppyMath.Haversin(40.7143528, -74.0059731, 40.7247222, -74), 0.01D);
Assert.AreEqual(2.029, SloppyMath.Haversin(40.7143528, -74.0059731, 40.731033, -73.9962255), 0.01D);
Assert.AreEqual(8.572, SloppyMath.Haversin(40.7143528, -74.0059731, 40.65, -73.95), 0.01D);
}
}
}