Skip to content

Commit

Permalink
* Implemented Int64Divisor
Browse files Browse the repository at this point in the history
  • Loading branch information
MineCake147E committed Sep 18, 2020
1 parent 5cec8ca commit b70a231
Show file tree
Hide file tree
Showing 11 changed files with 1,488 additions and 113 deletions.
6 changes: 0 additions & 6 deletions DivideSharp.Tests/Int32DivisionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,9 @@ private static IEnumerable<TestCaseData> DivisionTestCaseSource
yield return new TestCaseData(item, item - 1);
yield return new TestCaseData(item, item);
yield return new TestCaseData(item, item + 1);
yield return new TestCaseData(item, 2 * item - 1);
yield return new TestCaseData(item, 2 * item);
yield return new TestCaseData(item, 2 * item + 1);
yield return new TestCaseData(item, -item - 1);
yield return new TestCaseData(item, -item);
yield return new TestCaseData(item, -item + 1);
yield return new TestCaseData(item, 2 * -item - 1);
yield return new TestCaseData(item, 2 * -item);
yield return new TestCaseData(item, 2 * -item + 1);
}
//Branch
yield return new TestCaseData(int.MinValue, 1);
Expand Down
201 changes: 201 additions & 0 deletions DivideSharp.Tests/Int64DivisionTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
using System;
using System.Collections.Generic;
using System.Linq;

using Newtonsoft.Json;

using NUnit.Framework;

using TestAndBenchmarkUtils;

namespace DivideSharp.Tests
{
[TestFixture]
public class Int64DivisionTests
{
#region Test Cases

private static IEnumerable<long> Divisors
{
get
{
var divisors = new long[]
{
//Obvious
1,
//Pre-Defined
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
//Shift
2,
16,
15, //MultiplyAdd or MultiplySub
29 //Multiply
};
return divisors.Concat(divisors.Select(a => -a)).Distinct().OrderBy(a => Math.Abs(a));
}
}

private static IEnumerable<TestCaseData> RandomDivisionTestCaseSource => Divisors.Append(long.MinValue).Select(a => new TestCaseData(a));

private const ulong RandomTestCount = 0x1_0000ul;

private static IEnumerable<TestCaseData> DivisionTestCaseSource
{
get
{
var divisors = Divisors;
//Generate Test Data's
foreach (var item in divisors)
{
yield return new TestCaseData(item, 1);
yield return new TestCaseData(item, item - 1);
yield return new TestCaseData(item, item);
yield return new TestCaseData(item, item + 1);
yield return new TestCaseData(item, -item - 1);
yield return new TestCaseData(item, -item);
yield return new TestCaseData(item, -item + 1);
}
//Branch
yield return new TestCaseData(long.MinValue, 1);
yield return new TestCaseData(long.MinValue, long.MinValue);
yield return new TestCaseData(long.MinValue, -long.MaxValue);
yield return new TestCaseData(long.MinValue, 0);
yield return new TestCaseData(long.MinValue, long.MaxValue);
}
}

#endregion Test Cases

private static string SerializeDivisor(Int64Divisor divisor) => $"{JsonConvert.SerializeObject(divisor)}";

[TestCaseSource(nameof(DivisionTestCaseSource))]
public void CorrectlyDivides(long divisor, long testDividend)
{
var int64Divisor = new Int64Divisor(divisor);
var quotient = testDividend / int64Divisor;
Console.WriteLine($"quotient:{quotient}");
Assert.AreEqual(testDividend / divisor, quotient, SerializeDivisor(int64Divisor));
}

[TestCaseSource(nameof(DivisionTestCaseSource))]
public void CalculatesModulusCorrectly(long divisor, long testDividend)
{
var int64Divisor = new Int64Divisor(divisor);
var remainder = testDividend % int64Divisor;
Console.WriteLine($"remainder:{remainder}");
Assert.AreEqual(testDividend % divisor, remainder, SerializeDivisor(int64Divisor));
}

[TestCaseSource(nameof(DivisionTestCaseSource))]
public void DivRemReturnsCorrectly(long divisor, long testDividend)
{
var int64Divisor = new Int64Divisor(divisor);
var remainder = int64Divisor.DivRem(testDividend, out var quotient);
Console.WriteLine($"quotient:{quotient}, remainder:{remainder}");
Assert.Multiple(() =>
{
Assert.AreEqual(testDividend % divisor, remainder, SerializeDivisor(int64Divisor));
Assert.AreEqual(testDividend / divisor, quotient, SerializeDivisor(int64Divisor));
});
}

[TestCaseSource(nameof(DivisionTestCaseSource))]
public void CalculatesAbsFloorCorrectly(long divisor, long testDividend)
{
var int64Divisor = new Int64Divisor(divisor);
var rounded = int64Divisor.AbsFloor(testDividend);
Console.WriteLine($"rounded:{rounded}");
Assert.AreEqual(testDividend / divisor * divisor, rounded, SerializeDivisor(int64Divisor));
}

[TestCaseSource(nameof(DivisionTestCaseSource))]
public void CalculatesAbsFloorRemCorrectly(long divisor, long testDividend)
{
var int64Divisor = new Int64Divisor(divisor);
var remainder = int64Divisor.AbsFloorRem(testDividend, out var rounded);
Console.WriteLine($"rounded:{rounded}, remainder:{remainder}");
Assert.Multiple(() =>
{
Assert.AreEqual(testDividend % divisor, remainder, SerializeDivisor(int64Divisor));
Assert.AreEqual(testDividend / divisor * divisor, rounded, SerializeDivisor(int64Divisor));
});
}

[TestCaseSource(nameof(RandomDivisionTestCaseSource))]
public void CorrectlyDividesRandomNumerators(long divisor)
{
var int64Divisor = new Int64Divisor(divisor);
var rng = new PcgRandom();
for (ulong i = 0; i < RandomTestCount; i++)
{
var testDividend = unchecked(rng.Next() | ((long)rng.Next() << 32));
var quotient = testDividend / int64Divisor;
Assert.AreEqual(testDividend / divisor, quotient, $"Trying to test {testDividend} / {divisor}");
}
}

[TestCaseSource(nameof(RandomDivisionTestCaseSource))]
public void CalculatesModulusCorrectlyRandomNumerators(long divisor)
{
var int64Divisor = new Int64Divisor(divisor);
var rng = new PcgRandom();

for (ulong i = 0; i < RandomTestCount; i++)
{
var testDividend = unchecked(rng.Next() | ((long)rng.Next() << 32));
var remainder = testDividend % int64Divisor;
Assert.AreEqual(testDividend % divisor, remainder, $"Trying to test {testDividend} % {divisor}");
}
}

[TestCaseSource(nameof(RandomDivisionTestCaseSource))]
public void DivRemReturnsCorrectlyRandomNumerators(long divisor)
{
var int64Divisor = new Int64Divisor(divisor);
var rng = new PcgRandom();
for (ulong i = 0; i < RandomTestCount; i++)
{
var testDividend = unchecked(rng.Next() | ((long)rng.Next() << 32));
var remainder = int64Divisor.DivRem(testDividend, out var quotient);
Assert.AreEqual(testDividend % divisor, remainder, $"Trying to test {testDividend} % {divisor}");
Assert.AreEqual(testDividend / divisor, quotient, $"Trying to test {testDividend} / {divisor}");
}
}

[TestCaseSource(nameof(RandomDivisionTestCaseSource))]
public void CalculatesAbsFloorCorrectlyRandomNumerators(long divisor)
{
var int64Divisor = new Int64Divisor(divisor);
var rng = new PcgRandom();
for (ulong i = 0; i < RandomTestCount; i++)
{
var testDividend = unchecked(rng.Next() | ((long)rng.Next() << 32));
var rounded = int64Divisor.AbsFloor(testDividend);
Assert.AreEqual(testDividend / divisor * divisor, rounded, $"Trying to test {testDividend} / {divisor} * {divisor}");
}
}

[TestCaseSource(nameof(RandomDivisionTestCaseSource))]
public void CalculatesAbsFloorRemCorrectlyRandomNumerators(long divisor)
{
var int64Divisor = new Int64Divisor(divisor);
var rng = new PcgRandom();
for (ulong i = 0; i < RandomTestCount; i++)
{
var testDividend = unchecked(rng.Next() | ((long)rng.Next() << 32));
var remainder = int64Divisor.AbsFloorRem(testDividend, out var rounded);
Assert.AreEqual(testDividend % divisor, remainder, $"Trying to test {testDividend} % {divisor}");
Assert.AreEqual(testDividend / divisor * divisor, rounded, $"Trying to test {testDividend} / {divisor} * {divisor}");
}
}
}
}
47 changes: 46 additions & 1 deletion DivideSharp.Tests/MiscTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public static uint MultiplyHigh32(uint a, uint b)
}

[Test]
public void MulHiEquals()
public void MulHiEqualsUnsigned()
{
var rng = new PcgRandom();
for (ulong i = 0; i < RandomTestCount; i++)
Expand All @@ -48,5 +48,50 @@ public void MulHiEquals()
Assert.AreEqual(MultiplyHigh32(a, b), MultiplyHighCustom32(a, b), $"Testing {a} * {b}");
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int MultiplyHighCustom32(int x, int y)
{
unchecked
{
uint xl = (ushort)x;
uint yl = (ushort)y;
int xh = x >> 16;
int yh = y >> 16;
uint u = xl * yl;
int s = (int)(u >> 16);
int t1 = xh * (int)yl;
int t2 = yh * (int)xl;
s += (ushort)t1;
s += (ushort)t2;
s >>= 16;
s += (t1 >> 16) + (t2 >> 16);
s += xh * yh;
return s;
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int MultiplyHigh32(int a, int b)
{
long h = a;
h *= b;
return (int)(h >> 32);
}

[Test]
public void MulHiEqualsSigned()
{
unchecked
{
var rng = new PcgRandom();
for (ulong i = 0; i < RandomTestCount; i++)
{
var a = (int)rng.Next();
var b = (int)rng.Next();
Assert.AreEqual(MultiplyHigh32(a, b), MultiplyHighCustom32(a, b), $"Testing {a} * {b}");
}
}
}
}
}
Loading

0 comments on commit b70a231

Please sign in to comment.