Skip to content

Instantly share code, notes, and snippets.

@benaadams
Created October 14, 2019 15:00
Show Gist options
  • Save benaadams/b3ba5e45c1f0a13b649296a9660ea960 to your computer and use it in GitHub Desktop.
Save benaadams/b3ba5e45c1f0a13b649296a9660ea960 to your computer and use it in GitHub Desktop.
using System;
using System.Numerics;
using System.Runtime.Intrinsics.X86;
using static System.Console;
class Program
{
static void Main()
{
FillBuckets(bucketCount: 17, values: ..17);
FillBuckets(bucketCount: 17, values: ..24);
FillBuckets(bucketCount: 17, values: ..512);
FillBuckets(bucketCount: 17, values: ^17..);
}
static (string name, Func<uint, uint, uint> func)[] s_methods = new (string, Func<uint, uint, uint>)[]
{
(nameof(Modulo), Modulo),
(nameof(FastRange), FastRange),
(nameof(FastRangeCrcForward), FastRangeCrcForward),
(nameof(FastRangeCrcReversed), FastRangeCrcReversed),
(nameof(FastRangeRotR7Xor), FastRangeRotR7Xor),
(nameof(FastRangeRotR7XorX3), FastRangeRotR7XorX3),
(nameof(FastRangeXorShiftPlus), FastRangeXorShiftPlus)
};
static uint Modulo(uint index, uint range)
{
return index % range;
}
static uint FastRange(uint index, uint range)
{
return (uint)(((ulong)index * (ulong)range) >> 32);
}
static uint FastRangeCrcForward(uint index, uint range)
{
var reversedIndex = Sse42.Crc32(0x04C11DB7, index);
return (uint)((reversedIndex * (ulong)range) >> 32);
}
static uint FastRangeCrcReversed(uint index, uint range)
{
const uint CrcReflected = 0xEDB88320;
var reversedIndex = Sse42.Crc32(CrcReflected, index);
return (uint)((reversedIndex * (ulong)range) >> 32);
}
static uint FastRangeRotR7Xor(uint index, uint range)
{
index ^= BitOperations.RotateRight(index, 7);
return (uint)((index * (ulong)range) >> 32);
}
static uint FastRangeRotR7XorX3(uint index, uint range)
{
index ^= BitOperations.RotateRight(index, 7);
index ^= BitOperations.RotateRight(index, 7);
index ^= BitOperations.RotateRight(index, 7);
return (uint)((index * (ulong)range) >> 32);
}
static uint FastRangeXorShiftPlus(uint index, uint range)
{
const ulong seed = 0x04C11DB7_EDB88320;
const ulong finisher = seed ^ (seed >> 26) ^ (seed << 38);
ulong t = index;
t ^= BitOperations.RotateLeft(t, 23);
t ^= BitOperations.RotateRight(t, 17);
t ^= finisher;
index = (uint)(t + seed);
return (uint)((index * (ulong)range) >> 32);
}
private static void FillBuckets(uint bucketCount, Range values)
{
var (start, end) = GetStartEnd(values);
WriteLine($"Bucket count {bucketCount}, {(start < end ? end - start : start - end)} Values: {start} to {end} (exclusive)");
Initialize(bucketCount, values);
Write(string.Format("{0,21} ", "Method"));
WriteLine(" Bucket Load");
WriteLine(new string('-', 60));
for (int i = 0; i < s_ocurrances.Length; i++)
{
var occurs = s_ocurrances[i];
var method = s_methods[i];
Write(string.Format("{0,21} : ", method.name));
foreach (var item in occurs)
{
Write($"{string.Format("{0,6}", item.ToString())} ");
}
WriteLine();
}
WriteLine();
}
static int[][] s_ocurrances;
static (uint start, uint end) GetStartEnd(Range range)
{
var start = range.Start.IsFromEnd ? uint.MaxValue - range.Start.Value : range.Start.Value;
var end = range.End.IsFromEnd ? uint.MaxValue - range.End.Value : range.End.Value;
return ((uint)start, (uint)end);
}
static void Initialize(uint bucketCount, Range range)
{
var (start, end) = GetStartEnd(range);
s_ocurrances = new int[s_methods.Length][];
for (var o = 0; o < s_ocurrances.Length; o++)
{
var occurs = (s_ocurrances[o] = new int[bucketCount]);
var method = s_methods[o];
if (start > end)
{
for (var i = start; i > end; i--)
{
occurs[method.func((uint)i, bucketCount)]++;
}
}
else
{
for (var i = start; i < end; i++)
{
occurs[method.func((uint)i, bucketCount)]++;
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment