-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Made pre-generated divisors static * Added benchmarks on initialization * Found that initialization of `UInt32Divisor` is 13x slower than ordinal division
- Loading branch information
1 parent
ae3df17
commit 121939a
Showing
16 changed files
with
1,223 additions
and
112 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Runtime.CompilerServices; | ||
using System.Text; | ||
|
||
using NUnit.Framework; | ||
|
||
using TestAndBenchmarkUtils; | ||
|
||
namespace DivideSharp.Tests | ||
{ | ||
[TestFixture] | ||
public class MiscTests | ||
{ | ||
private const ulong RandomTestCount = 0x1_0000ul; | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public static uint MultiplyHighCustom32(uint a, uint b) | ||
{ | ||
uint al = (ushort)a; | ||
uint ah = a >> 16; | ||
uint bl = (ushort)b; | ||
uint bh = b >> 16; | ||
uint u = al * bl; | ||
uint t = ah * bl + (u >> 16); | ||
uint tl = (ushort)t; | ||
uint th = t >> 16; | ||
tl += al * bh; | ||
return ah * bh + th + (tl >> 16); | ||
} | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public static uint MultiplyHigh32(uint a, uint b) | ||
{ | ||
ulong h = a; | ||
h *= b; | ||
return (uint)(h >> 32); | ||
} | ||
|
||
[Test] | ||
public void MulHiEquals() | ||
{ | ||
var rng = new PcgRandom(); | ||
for (ulong i = 0; i < RandomTestCount; i++) | ||
{ | ||
var a = rng.Next(); | ||
var b = rng.Next(); | ||
Assert.AreEqual(MultiplyHigh32(a, b), MultiplyHighCustom32(a, b), $"Testing {a} * {b}"); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Runtime.CompilerServices; | ||
|
||
using Newtonsoft.Json; | ||
|
||
using NUnit.Framework; | ||
|
||
using TestAndBenchmarkUtils; | ||
|
||
namespace DivideSharp.Tests | ||
{ | ||
[TestFixture] | ||
public class UInt64DivisionTests | ||
{ | ||
#region Test Cases | ||
|
||
private static IEnumerable<ulong> Divisors => new ulong[] | ||
{ | ||
//Obvious | ||
1, | ||
//Pre-Defined | ||
3, | ||
4, | ||
5, | ||
6, | ||
7, | ||
8, | ||
9, | ||
10, | ||
11, | ||
12, | ||
//Shift | ||
2, | ||
16, | ||
19, //MultiplyAdd | ||
23 //Multiply | ||
}; | ||
|
||
private static IEnumerable<TestCaseData> RandomDivisionTestCaseSource => Divisors.Append(0x8000_0000_0000_0001u).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, 1u); | ||
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(0x8000_0000_0000_0001u, 1u); | ||
yield return new TestCaseData(0x8000_0000_0000_0001u, 0x8000_0000_0000_0000u); | ||
yield return new TestCaseData(0x8000_0000_0000_0001u, 0x8000_0000_0000_0001u); | ||
yield return new TestCaseData(0x8000_0000_0000_0001u, 0x8000_0000_0000_0002u); | ||
yield return new TestCaseData(0x8000_0000_0000_0001u, 0xFFFF_FFFF_FFFF_FFFEu); | ||
yield return new TestCaseData(0x8000_0000_0000_0001u, 0xFFFF_FFFF_FFFF_FFFFu); | ||
} | ||
} | ||
|
||
#endregion Test Cases | ||
|
||
private static string SerializeDivisor(UInt64Divisor divisor) => $"{JsonConvert.SerializeObject(divisor)}"; | ||
|
||
[TestCaseSource(nameof(DivisionTestCaseSource))] | ||
public void CorrectlyDivides(ulong divisor, ulong testDividend) | ||
{ | ||
var uInt64Divisor = new UInt64Divisor(divisor); | ||
var quotient = testDividend / uInt64Divisor; | ||
Assert.AreEqual(testDividend / divisor, quotient, SerializeDivisor(uInt64Divisor)); | ||
} | ||
|
||
[TestCaseSource(nameof(DivisionTestCaseSource))] | ||
public void CalculatesModulusCorrectly(ulong divisor, ulong testDividend) | ||
{ | ||
var uInt64Divisor = new UInt64Divisor(divisor); | ||
var remainder = testDividend % uInt64Divisor; | ||
Assert.AreEqual(testDividend % divisor, remainder, SerializeDivisor(uInt64Divisor)); | ||
} | ||
|
||
[TestCaseSource(nameof(DivisionTestCaseSource))] | ||
public void DivRemReturnsCorrectly(ulong divisor, ulong testDividend) | ||
{ | ||
var uInt64Divisor = new UInt64Divisor(divisor); | ||
var remainder = uInt64Divisor.DivRem(testDividend, out var quotient); | ||
Assert.Multiple(() => | ||
{ | ||
Assert.AreEqual(testDividend % divisor, remainder, SerializeDivisor(uInt64Divisor)); | ||
Assert.AreEqual(testDividend / divisor, quotient, SerializeDivisor(uInt64Divisor)); | ||
}); | ||
} | ||
|
||
[TestCaseSource(nameof(DivisionTestCaseSource))] | ||
public void CalculatesFloorCorrectly(ulong divisor, ulong testDividend) | ||
{ | ||
var uInt64Divisor = new UInt64Divisor(divisor); | ||
var rounded = uInt64Divisor.Floor(testDividend); | ||
Assert.AreEqual(testDividend / divisor * divisor, rounded, SerializeDivisor(uInt64Divisor)); | ||
} | ||
|
||
[TestCaseSource(nameof(DivisionTestCaseSource))] | ||
public void CalculatesFloorRemCorrectly(ulong divisor, ulong testDividend) | ||
{ | ||
var uInt64Divisor = new UInt64Divisor(divisor); | ||
var remainder = uInt64Divisor.FloorRem(testDividend, out var rounded); | ||
Assert.Multiple(() => | ||
{ | ||
Assert.AreEqual(testDividend % divisor, remainder, SerializeDivisor(uInt64Divisor)); | ||
Assert.AreEqual(testDividend / divisor * divisor, rounded, SerializeDivisor(uInt64Divisor)); | ||
}); | ||
} | ||
|
||
[TestCaseSource(nameof(RandomDivisionTestCaseSource))] | ||
public void CorrectlyDividesRandomNumerators(ulong divisor) | ||
{ | ||
var uInt64Divisor = new UInt64Divisor(divisor); | ||
var rng = new PcgRandom(); | ||
for (ulong i = 0; i < RandomTestCount; i++) | ||
{ | ||
var testDividend = rng.Next() | ((ulong)rng.Next() << 32); | ||
var quotient = testDividend / uInt64Divisor; | ||
Assert.AreEqual(testDividend / divisor, quotient, $"Trying to test {testDividend} / {SerializeDivisor(uInt64Divisor)}"); | ||
} | ||
} | ||
|
||
[TestCaseSource(nameof(RandomDivisionTestCaseSource))] | ||
public void CalculatesModulusCorrectlyRandomNumerators(ulong divisor) | ||
{ | ||
var uInt64Divisor = new UInt64Divisor(divisor); | ||
var rng = new PcgRandom(); | ||
|
||
for (ulong i = 0; i < RandomTestCount; i++) | ||
{ | ||
var testDividend = rng.Next() | ((ulong)rng.Next() << 32); | ||
var remainder = testDividend % uInt64Divisor; | ||
Assert.AreEqual(testDividend % divisor, remainder, $"Trying to test {testDividend} % {SerializeDivisor(uInt64Divisor)}"); | ||
} | ||
} | ||
|
||
[TestCaseSource(nameof(RandomDivisionTestCaseSource))] | ||
public void DivRemReturnsCorrectlyRandomNumerators(ulong divisor) | ||
{ | ||
var uInt64Divisor = new UInt64Divisor(divisor); | ||
var rng = new PcgRandom(); | ||
for (ulong i = 0; i < RandomTestCount; i++) | ||
{ | ||
var testDividend = rng.Next() | ((ulong)rng.Next() << 32); | ||
var remainder = uInt64Divisor.DivRem(testDividend, out var quotient); | ||
Assert.AreEqual(testDividend % divisor, remainder, $"Trying to test {testDividend} % {SerializeDivisor(uInt64Divisor)}"); | ||
Assert.AreEqual(testDividend / divisor, quotient, $"Trying to test {testDividend} / {SerializeDivisor(uInt64Divisor)}"); | ||
} | ||
} | ||
|
||
[TestCaseSource(nameof(RandomDivisionTestCaseSource))] | ||
public void CalculatesFloorCorrectlyRandomNumerators(ulong divisor) | ||
{ | ||
var uInt64Divisor = new UInt64Divisor(divisor); | ||
var rng = new PcgRandom(); | ||
for (ulong i = 0; i < RandomTestCount; i++) | ||
{ | ||
var testDividend = rng.Next() | ((ulong)rng.Next() << 32); | ||
var rounded = uInt64Divisor.Floor(testDividend); | ||
Assert.AreEqual(testDividend / divisor * divisor, rounded, $"Trying to test {testDividend} / {SerializeDivisor(uInt64Divisor)} * {SerializeDivisor(uInt64Divisor)}"); | ||
} | ||
} | ||
|
||
[TestCaseSource(nameof(RandomDivisionTestCaseSource))] | ||
public void CalculatesFloorRemCorrectlyRandomNumerators(ulong divisor) | ||
{ | ||
var uInt64Divisor = new UInt64Divisor(divisor); | ||
var rng = new PcgRandom(); | ||
for (ulong i = 0; i < RandomTestCount; i++) | ||
{ | ||
var testDividend = rng.Next() | ((ulong)rng.Next() << 32); | ||
var remainder = uInt64Divisor.FloorRem(testDividend, out var rounded); | ||
Assert.AreEqual(testDividend % divisor, remainder, $"Trying to test {testDividend} % {SerializeDivisor(uInt64Divisor)}"); | ||
Assert.AreEqual(testDividend / divisor * divisor, rounded, $"Trying to test {testDividend} / {SerializeDivisor(uInt64Divisor)} * {SerializeDivisor(uInt64Divisor)}"); | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.