M src/Benchmarks/UniformDists.cs +30 -8
@@ 13,14 13,16 @@ namespace RandN.Benchmarks
private readonly StepRng _rng;
- private readonly UniformSByte _uniformSByte;
- private readonly UniformInt16 _uniformInt16;
- private readonly UniformInt32 _uniformInt32;
- private readonly UniformInt64 _uniformInt64;
- private readonly UniformByte _uniformByte;
- private readonly UniformUInt16 _uniformUInt16;
- private readonly UniformUInt32 _uniformUInt32;
- private readonly UniformUInt64 _uniformUInt64;
+ private readonly UniformInt<SByte> _uniformSByte;
+ private readonly UniformInt<Int16> _uniformInt16;
+ private readonly UniformInt<Int32> _uniformInt32;
+ private readonly UniformInt32 _uniformInt32Original;
+ private readonly UniformInt<Int64> _uniformInt64;
+ private readonly UniformInt64 _uniformInt64Original;
+ private readonly UniformInt<Byte> _uniformByte;
+ private readonly UniformInt<UInt16> _uniformUInt16;
+ private readonly UniformInt<UInt32> _uniformUInt32;
+ private readonly UniformInt<UInt64> _uniformUInt64;
private readonly UniformFloat<Single> _uniformSingle;
private readonly UniformFloat<Double> _uniformDouble;
@@ 38,7 40,9 @@ namespace RandN.Benchmarks
_uniformByte = Uniform.New((Byte)LowerBound, (Byte)UpperBound);
_uniformUInt16 = Uniform.New((UInt16)LowerBound, (UInt16)UpperBound);
_uniformUInt32 = Uniform.New((UInt32)LowerBound, (UInt32)UpperBound);
+ _uniformInt32Original = UniformInt32.Create(LowerBound, UpperBound);
_uniformUInt64 = Uniform.New((UInt64)LowerBound, (UInt64)UpperBound);
+ _uniformInt64Original = UniformInt64.Create(LowerBound, UpperBound);
_uniformSingle = Uniform.New((Single)LowerBound, (Single)UpperBound);
_uniformDouble = Uniform.New((Double)LowerBound, (Double)UpperBound);
@@ 74,6 78,15 @@ namespace RandN.Benchmarks
}
[Benchmark]
+ public Int32 SampleInt32Original()
+ {
+ Int32 sum = 0;
+ for (Int32 i = 0; i < Iterations; i++)
+ sum = unchecked(sum + _uniformInt32Original.Sample(_rng));
+ return sum;
+ }
+
+ [Benchmark]
public Int64 SampleInt64()
{
Int64 sum = 0;
@@ 83,6 96,15 @@ namespace RandN.Benchmarks
}
[Benchmark]
+ public Int64 SampleInt64Original()
+ {
+ Int64 sum = 0;
+ for (Int32 i = 0; i < Iterations; i++)
+ sum = unchecked(sum + _uniformInt64Original.Sample(_rng));
+ return sum;
+ }
+
+ [Benchmark]
public UInt32 SampleByte()
{
UInt32 sum = 0;
M src/RandN/Distributions/Uniform.cs +161 -168
@@ 21,174 21,6 @@ namespace RandN.Distributions
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
/// </exception>
- public static UniformSByte New(SByte low, SByte high) => UniformSByte.Create(low, high);
-
- /// <summary>
- /// Creates uniform distribution in the interval [low, high], inclusive of low and high.
- /// </summary>
- /// <param name="low">The inclusive lower bound.</param>
- /// <param name="high">The inclusive upper bound.</param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// Thrown when <paramref name="low"/> is greater than <paramref name="high"/>.
- /// </exception>
- public static UniformSByte NewInclusive(SByte low, SByte high) => UniformSByte.CreateInclusive(low, high);
-
-
- /// <summary>
- /// Creates uniform distribution in the interval [low, high), inclusive of low and exclusive of high.
- /// </summary>
- /// <param name="low">The inclusive lower bound.</param>
- /// <param name="high">The exclusive upper bound.</param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
- /// </exception>
- public static UniformInt16 New(Int16 low, Int16 high) => UniformInt16.Create(low, high);
-
- /// <summary>
- /// Creates uniform distribution in the interval [low, high], inclusive of low and high.
- /// </summary>
- /// <param name="low">The inclusive lower bound.</param>
- /// <param name="high">The inclusive upper bound.</param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// Thrown when <paramref name="low"/> is greater than <paramref name="high"/>.
- /// </exception>
- public static UniformInt16 NewInclusive(Int16 low, Int16 high) => UniformInt16.CreateInclusive(low, high);
-
-
- /// <summary>
- /// Creates uniform distribution in the interval [low, high), inclusive of low and exclusive of high.
- /// </summary>
- /// <param name="low">The inclusive lower bound.</param>
- /// <param name="high">The exclusive upper bound.</param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
- /// </exception>
- public static UniformInt32 New(Int32 low, Int32 high) => UniformInt32.Create(low, high);
-
- /// <summary>
- /// Creates uniform distribution in the interval [low, high], inclusive of low and high.
- /// </summary>
- /// <param name="low">The inclusive lower bound.</param>
- /// <param name="high">The inclusive upper bound.</param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// Thrown when <paramref name="low"/> is greater than <paramref name="high"/>.
- /// </exception>
- public static UniformInt32 NewInclusive(Int32 low, Int32 high) => UniformInt32.CreateInclusive(low, high);
-
-
- /// <summary>
- /// Creates uniform distribution in the interval [low, high), inclusive of low and exclusive of high.
- /// </summary>
- /// <param name="low">The inclusive lower bound.</param>
- /// <param name="high">The exclusive upper bound.</param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
- /// </exception>
- public static UniformInt64 New(Int64 low, Int64 high) => UniformInt64.Create(low, high);
-
- /// <summary>
- /// Creates uniform distribution in the interval [low, high], inclusive of low and high.
- /// </summary>
- /// <param name="low">The inclusive lower bound.</param>
- /// <param name="high">The inclusive upper bound.</param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// Thrown when <paramref name="low"/> is greater than <paramref name="high"/>.
- /// </exception>
- public static UniformInt64 NewInclusive(Int64 low, Int64 high) => UniformInt64.CreateInclusive(low, high);
-
-
- /// <summary>
- /// Creates uniform distribution in the interval [low, high), inclusive of low and exclusive of high.
- /// </summary>
- /// <param name="low">The inclusive lower bound.</param>
- /// <param name="high">The exclusive upper bound.</param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
- /// </exception>
- public static UniformByte New(Byte low, Byte high) => UniformByte.Create(low, high);
-
- /// <summary>
- /// Creates uniform distribution in the interval [low, high], inclusive of low and high.
- /// </summary>
- /// <param name="low">The inclusive lower bound.</param>
- /// <param name="high">The inclusive upper bound.</param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// Thrown when <paramref name="low"/> is greater than <paramref name="high"/>.
- /// </exception>
- public static UniformByte NewInclusive(Byte low, Byte high) => UniformByte.CreateInclusive(low, high);
-
-
- /// <summary>
- /// Creates uniform distribution in the interval [low, high), inclusive of low and exclusive of high.
- /// </summary>
- /// <param name="low">The inclusive lower bound.</param>
- /// <param name="high">The exclusive upper bound.</param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
- /// </exception>
- public static UniformUInt16 New(UInt16 low, UInt16 high) => UniformUInt16.Create(low, high);
-
- /// <summary>
- /// Creates uniform distribution in the interval [low, high], inclusive of low and high.
- /// </summary>
- /// <param name="low">The inclusive lower bound.</param>
- /// <param name="high">The inclusive upper bound.</param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// Thrown when <paramref name="low"/> is greater than <paramref name="high"/>.
- /// </exception>
- public static UniformUInt16 NewInclusive(UInt16 low, UInt16 high) => UniformUInt16.CreateInclusive(low, high);
-
-
- /// <summary>
- /// Creates uniform distribution in the interval [low, high), inclusive of low and exclusive of high.
- /// </summary>
- /// <param name="low">The inclusive lower bound.</param>
- /// <param name="high">The exclusive upper bound.</param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
- /// </exception>
- public static UniformUInt32 New(UInt32 low, UInt32 high) => UniformUInt32.Create(low, high);
-
- /// <summary>
- /// Creates uniform distribution in the interval [low, high], inclusive of low and high.
- /// </summary>
- /// <param name="low">The inclusive lower bound.</param>
- /// <param name="high">The inclusive upper bound.</param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// Thrown when <paramref name="low"/> is greater than <paramref name="high"/>.
- /// </exception>
- public static UniformUInt32 NewInclusive(UInt32 low, UInt32 high) => UniformUInt32.CreateInclusive(low, high);
-
-
- /// <summary>
- /// Creates uniform distribution in the interval [low, high), inclusive of low and exclusive of high.
- /// </summary>
- /// <param name="low">The inclusive lower bound.</param>
- /// <param name="high">The exclusive upper bound.</param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
- /// </exception>
- public static UniformUInt64 New(UInt64 low, UInt64 high) => UniformUInt64.Create(low, high);
-
- /// <summary>
- /// Creates uniform distribution in the interval [low, high], inclusive of low and high.
- /// </summary>
- /// <param name="low">The inclusive lower bound.</param>
- /// <param name="high">The inclusive upper bound.</param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// Thrown when <paramref name="low"/> is greater than <paramref name="high"/>.
- /// </exception>
- public static UniformUInt64 NewInclusive(UInt64 low, UInt64 high) => UniformUInt64.CreateInclusive(low, high);
-
-
- /// <summary>
- /// Creates uniform distribution in the interval [low, high), inclusive of low and exclusive of high.
- /// </summary>
- /// <param name="low">The inclusive lower bound.</param>
- /// <param name="high">The exclusive upper bound.</param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
- /// </exception>
public static UniformTimeSpan New(TimeSpan low, TimeSpan high) => UniformTimeSpan.Create(low, high);
/// <summary>
@@ 223,6 55,167 @@ namespace RandN.Distributions
public static UniformDecimal NewInclusive(Decimal low, Decimal high) => UniformDecimal.CreateInclusive(low, high);
+
+ /// <summary>
+ /// Creates uniform distribution in the interval [low, high), inclusive of low and exclusive of high.
+ /// </summary>
+ /// <param name="low">The inclusive lower bound.</param>
+ /// <param name="high">The exclusive upper bound.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<SByte> New(SByte low, SByte high) => UniformInt.Create(low, high);
+
+ /// <summary>
+ /// Creates uniform distribution in the interval [low, high], inclusive of low and high.
+ /// </summary>
+ /// <param name="low">The inclusive lower bound.</param>
+ /// <param name="high">The inclusive upper bound.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<SByte> NewInclusive(SByte low, SByte high) => UniformInt.CreateInclusive(low, high);
+
+ /// <summary>
+ /// Creates uniform distribution in the interval [low, high), inclusive of low and exclusive of high.
+ /// </summary>
+ /// <param name="low">The inclusive lower bound.</param>
+ /// <param name="high">The exclusive upper bound.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<Int16> New(Int16 low, Int16 high) => UniformInt.Create(low, high);
+
+ /// <summary>
+ /// Creates uniform distribution in the interval [low, high], inclusive of low and high.
+ /// </summary>
+ /// <param name="low">The inclusive lower bound.</param>
+ /// <param name="high">The inclusive upper bound.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<Int16> NewInclusive(Int16 low, Int16 high) => UniformInt.CreateInclusive(low, high);
+
+ /// <summary>
+ /// Creates uniform distribution in the interval [low, high), inclusive of low and exclusive of high.
+ /// </summary>
+ /// <param name="low">The inclusive lower bound.</param>
+ /// <param name="high">The exclusive upper bound.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<Int32> New(Int32 low, Int32 high) => UniformInt.Create(low, high);
+
+ /// <summary>
+ /// Creates uniform distribution in the interval [low, high], inclusive of low and high.
+ /// </summary>
+ /// <param name="low">The inclusive lower bound.</param>
+ /// <param name="high">The inclusive upper bound.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<Int32> NewInclusive(Int32 low, Int32 high) => UniformInt.CreateInclusive(low, high);
+
+ /// <summary>
+ /// Creates uniform distribution in the interval [low, high), inclusive of low and exclusive of high.
+ /// </summary>
+ /// <param name="low">The inclusive lower bound.</param>
+ /// <param name="high">The exclusive upper bound.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<Int64> New(Int64 low, Int64 high) => UniformInt.Create(low, high);
+
+ /// <summary>
+ /// Creates uniform distribution in the interval [low, high], inclusive of low and high.
+ /// </summary>
+ /// <param name="low">The inclusive lower bound.</param>
+ /// <param name="high">The inclusive upper bound.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<Int64> NewInclusive(Int64 low, Int64 high) => UniformInt.CreateInclusive(low, high);
+
+ /// <summary>
+ /// Creates uniform distribution in the interval [low, high), inclusive of low and exclusive of high.
+ /// </summary>
+ /// <param name="low">The inclusive lower bound.</param>
+ /// <param name="high">The exclusive upper bound.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<Byte> New(Byte low, Byte high) => UniformInt.Create(low, high);
+
+ /// <summary>
+ /// Creates uniform distribution in the interval [low, high], inclusive of low and high.
+ /// </summary>
+ /// <param name="low">The inclusive lower bound.</param>
+ /// <param name="high">The inclusive upper bound.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<Byte> NewInclusive(Byte low, Byte high) => UniformInt.CreateInclusive(low, high);
+
+ /// <summary>
+ /// Creates uniform distribution in the interval [low, high), inclusive of low and exclusive of high.
+ /// </summary>
+ /// <param name="low">The inclusive lower bound.</param>
+ /// <param name="high">The exclusive upper bound.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<UInt16> New(UInt16 low, UInt16 high) => UniformInt.Create(low, high);
+
+ /// <summary>
+ /// Creates uniform distribution in the interval [low, high], inclusive of low and high.
+ /// </summary>
+ /// <param name="low">The inclusive lower bound.</param>
+ /// <param name="high">The inclusive upper bound.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<UInt16> NewInclusive(UInt16 low, UInt16 high) => UniformInt.CreateInclusive(low, high);
+
+ /// <summary>
+ /// Creates uniform distribution in the interval [low, high), inclusive of low and exclusive of high.
+ /// </summary>
+ /// <param name="low">The inclusive lower bound.</param>
+ /// <param name="high">The exclusive upper bound.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<UInt32> New(UInt32 low, UInt32 high) => UniformInt.Create(low, high);
+
+ /// <summary>
+ /// Creates uniform distribution in the interval [low, high], inclusive of low and high.
+ /// </summary>
+ /// <param name="low">The inclusive lower bound.</param>
+ /// <param name="high">The inclusive upper bound.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<UInt32> NewInclusive(UInt32 low, UInt32 high) => UniformInt.CreateInclusive(low, high);
+
+ /// <summary>
+ /// Creates uniform distribution in the interval [low, high), inclusive of low and exclusive of high.
+ /// </summary>
+ /// <param name="low">The inclusive lower bound.</param>
+ /// <param name="high">The exclusive upper bound.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<UInt64> New(UInt64 low, UInt64 high) => UniformInt.Create(low, high);
+
+ /// <summary>
+ /// Creates uniform distribution in the interval [low, high], inclusive of low and high.
+ /// </summary>
+ /// <param name="low">The inclusive lower bound.</param>
+ /// <param name="high">The inclusive upper bound.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<UInt64> NewInclusive(UInt64 low, UInt64 high) => UniformInt.CreateInclusive(low, high);
+
/// <summary>
/// Creates uniform distribution in the interval [low, high), inclusive of low and exclusive of high.
/// </summary>
M src/RandN/Distributions/Uniform.tt +32 -2
@@ 4,6 4,11 @@
<#
var types = new Type[]
{
+ typeof(TimeSpan),
+ typeof(Decimal),
+};
+var genericTypes = new Type[]
+{
typeof(SByte),
typeof(Int16),
typeof(Int32),
@@ 12,8 17,6 @@ var types = new Type[]
typeof(UInt16),
typeof(UInt32),
typeof(UInt64),
- typeof(TimeSpan),
- typeof(Decimal),
};
#>
using System;
@@ 54,6 57,33 @@ foreach (var type in types)
<#
}
#>
+<#
+foreach (var type in genericTypes)
+{
+ String typeName = type.Name;
+#>
+ /// <summary>
+ /// Creates uniform distribution in the interval [low, high), inclusive of low and exclusive of high.
+ /// </summary>
+ /// <param name="low">The inclusive lower bound.</param>
+ /// <param name="high">The exclusive upper bound.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<<#= typeName #>> New(<#= typeName #> low, <#= typeName #> high) => UniformInt.Create(low, high);
+
+ /// <summary>
+ /// Creates uniform distribution in the interval [low, high], inclusive of low and high.
+ /// </summary>
+ /// <param name="low">The inclusive lower bound.</param>
+ /// <param name="high">The inclusive upper bound.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<<#= typeName #>> NewInclusive(<#= typeName #> low, <#= typeName #> high) => UniformInt.CreateInclusive(low, high);
+<#
+}
+#>
/// <summary>
/// Creates uniform distribution in the interval [low, high), inclusive of low and exclusive of high.
/// </summary>
M src/RandN/Distributions/UniformFloat.cs +1 -1
@@ 178,7 178,7 @@ namespace RandN.Distributions
/// Use of any other type results in a runtime exception.
/// </summary>
public readonly struct UniformFloat<T> : IDistribution<T>
- // We're extremely restrictive here to discourage people from trying to use non-supported type for T
+ // We're extremely restrictive here to discourage people from trying to use unsupported types for T
where T : struct, IComparable, IComparable<T>, IConvertible, IEquatable<T>, IFormattable
{
private readonly T _low;
M src/RandN/Distributions/UniformFloat.tt +1 -1
@@ 111,7 111,7 @@ namespace RandN.Distributions
/// Use of any other type results in a runtime exception.
/// </summary>
public readonly struct UniformFloat<T> : IDistribution<T>
- // We're extremely restrictive here to discourage people from trying to use non-supported type for T
+ // We're extremely restrictive here to discourage people from trying to use unsupported types for T
where T : struct, IComparable, IComparable<T>, IConvertible, IEquatable<T>, IFormattable
{
private readonly T _low;
M src/RandN/Distributions/UniformInt.cs +370 -0
@@ 4,10 4,380 @@
using System;
+using Genumerics;
/*** This file is auto generated - any changes made here will be lost. ***/
namespace RandN.Distributions
{
+ internal static class UniformInt
+ {
+
+
+ /// <summary>
+ /// Creates a <see cref="UniformSByte" /> with an exclusive upper bound. Should not
+ /// be used directly; instead, use <see cref="Uniform.New(SByte, SByte)" />.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<SByte> Create(SByte low, SByte high)
+ {
+ if (low >= high)
+ throw new ArgumentOutOfRangeException(nameof(high), $"{nameof(high)} ({high}) must be higher than {nameof(low)} ({low}).");
+
+ return CreateInclusive(low, (SByte)(high - 1));
+ }
+
+
+ /// <summary>
+ /// Creates a <see cref="UniformSByte" /> with an exclusive lower bound. Should not
+ /// be used directly; instead, use <see cref="Uniform.NewInclusive(SByte, SByte)" />.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<SByte> CreateInclusive(SByte low, SByte high)
+ {
+ if (low > high)
+ throw new ArgumentOutOfRangeException(nameof(high), $"{nameof(high)} ({high}) must be higher than or equal to {nameof(low)} ({low}).");
+
+ var unsignedMax = UInt32.MaxValue;
+ var range = unchecked((UInt32)(high - low + 1));
+ var intsToReject = range == 0 ? 0 : (unsignedMax - range + 1) % range;
+
+ return new UniformInt<SByte>(low, range, (Byte)intsToReject);
+ }
+
+
+ /// <summary>
+ /// Creates a <see cref="UniformInt16" /> with an exclusive upper bound. Should not
+ /// be used directly; instead, use <see cref="Uniform.New(Int16, Int16)" />.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<Int16> Create(Int16 low, Int16 high)
+ {
+ if (low >= high)
+ throw new ArgumentOutOfRangeException(nameof(high), $"{nameof(high)} ({high}) must be higher than {nameof(low)} ({low}).");
+
+ return CreateInclusive(low, (Int16)(high - 1));
+ }
+
+
+ /// <summary>
+ /// Creates a <see cref="UniformInt16" /> with an exclusive lower bound. Should not
+ /// be used directly; instead, use <see cref="Uniform.NewInclusive(Int16, Int16)" />.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<Int16> CreateInclusive(Int16 low, Int16 high)
+ {
+ if (low > high)
+ throw new ArgumentOutOfRangeException(nameof(high), $"{nameof(high)} ({high}) must be higher than or equal to {nameof(low)} ({low}).");
+
+ var unsignedMax = UInt32.MaxValue;
+ var range = unchecked((UInt32)(high - low + 1));
+ var intsToReject = range == 0 ? 0 : (unsignedMax - range + 1) % range;
+
+ return new UniformInt<Int16>(low, range, (UInt16)intsToReject);
+ }
+
+
+ /// <summary>
+ /// Creates a <see cref="UniformInt32" /> with an exclusive upper bound. Should not
+ /// be used directly; instead, use <see cref="Uniform.New(Int32, Int32)" />.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<Int32> Create(Int32 low, Int32 high)
+ {
+ if (low >= high)
+ throw new ArgumentOutOfRangeException(nameof(high), $"{nameof(high)} ({high}) must be higher than {nameof(low)} ({low}).");
+
+ return CreateInclusive(low, (Int32)(high - 1));
+ }
+
+
+ /// <summary>
+ /// Creates a <see cref="UniformInt32" /> with an exclusive lower bound. Should not
+ /// be used directly; instead, use <see cref="Uniform.NewInclusive(Int32, Int32)" />.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<Int32> CreateInclusive(Int32 low, Int32 high)
+ {
+ if (low > high)
+ throw new ArgumentOutOfRangeException(nameof(high), $"{nameof(high)} ({high}) must be higher than or equal to {nameof(low)} ({low}).");
+
+ var unsignedMax = UInt32.MaxValue;
+ var range = unchecked((UInt32)(high - low + 1));
+ var intsToReject = range == 0 ? 0 : (unsignedMax - range + 1) % range;
+
+ return new UniformInt<Int32>(low, range, (UInt32)intsToReject);
+ }
+
+
+ /// <summary>
+ /// Creates a <see cref="UniformInt64" /> with an exclusive upper bound. Should not
+ /// be used directly; instead, use <see cref="Uniform.New(Int64, Int64)" />.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<Int64> Create(Int64 low, Int64 high)
+ {
+ if (low >= high)
+ throw new ArgumentOutOfRangeException(nameof(high), $"{nameof(high)} ({high}) must be higher than {nameof(low)} ({low}).");
+
+ return CreateInclusive(low, (Int64)(high - 1));
+ }
+
+
+ /// <summary>
+ /// Creates a <see cref="UniformInt64" /> with an exclusive lower bound. Should not
+ /// be used directly; instead, use <see cref="Uniform.NewInclusive(Int64, Int64)" />.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<Int64> CreateInclusive(Int64 low, Int64 high)
+ {
+ if (low > high)
+ throw new ArgumentOutOfRangeException(nameof(high), $"{nameof(high)} ({high}) must be higher than or equal to {nameof(low)} ({low}).");
+
+ var unsignedMax = UInt64.MaxValue;
+ var range = unchecked((UInt64)(high - low + 1));
+ var intsToReject = range == 0 ? 0 : (unsignedMax - range + 1) % range;
+
+ return new UniformInt<Int64>(low, range, (UInt64)intsToReject);
+ }
+
+
+ /// <summary>
+ /// Creates a <see cref="UniformByte" /> with an exclusive upper bound. Should not
+ /// be used directly; instead, use <see cref="Uniform.New(Byte, Byte)" />.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<Byte> Create(Byte low, Byte high)
+ {
+ if (low >= high)
+ throw new ArgumentOutOfRangeException(nameof(high), $"{nameof(high)} ({high}) must be higher than {nameof(low)} ({low}).");
+
+ return CreateInclusive(low, (Byte)(high - 1));
+ }
+
+
+ /// <summary>
+ /// Creates a <see cref="UniformByte" /> with an exclusive lower bound. Should not
+ /// be used directly; instead, use <see cref="Uniform.NewInclusive(Byte, Byte)" />.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<Byte> CreateInclusive(Byte low, Byte high)
+ {
+ if (low > high)
+ throw new ArgumentOutOfRangeException(nameof(high), $"{nameof(high)} ({high}) must be higher than or equal to {nameof(low)} ({low}).");
+
+ var unsignedMax = UInt32.MaxValue;
+ var range = unchecked((UInt32)(high - low + 1));
+ var intsToReject = range == 0 ? 0 : (unsignedMax - range + 1) % range;
+
+ return new UniformInt<Byte>(low, range, (Byte)intsToReject);
+ }
+
+
+ /// <summary>
+ /// Creates a <see cref="UniformUInt16" /> with an exclusive upper bound. Should not
+ /// be used directly; instead, use <see cref="Uniform.New(UInt16, UInt16)" />.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<UInt16> Create(UInt16 low, UInt16 high)
+ {
+ if (low >= high)
+ throw new ArgumentOutOfRangeException(nameof(high), $"{nameof(high)} ({high}) must be higher than {nameof(low)} ({low}).");
+
+ return CreateInclusive(low, (UInt16)(high - 1));
+ }
+
+
+ /// <summary>
+ /// Creates a <see cref="UniformUInt16" /> with an exclusive lower bound. Should not
+ /// be used directly; instead, use <see cref="Uniform.NewInclusive(UInt16, UInt16)" />.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<UInt16> CreateInclusive(UInt16 low, UInt16 high)
+ {
+ if (low > high)
+ throw new ArgumentOutOfRangeException(nameof(high), $"{nameof(high)} ({high}) must be higher than or equal to {nameof(low)} ({low}).");
+
+ var unsignedMax = UInt32.MaxValue;
+ var range = unchecked((UInt32)(high - low + 1));
+ var intsToReject = range == 0 ? 0 : (unsignedMax - range + 1) % range;
+
+ return new UniformInt<UInt16>(low, range, (UInt16)intsToReject);
+ }
+
+
+ /// <summary>
+ /// Creates a <see cref="UniformUInt32" /> with an exclusive upper bound. Should not
+ /// be used directly; instead, use <see cref="Uniform.New(UInt32, UInt32)" />.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<UInt32> Create(UInt32 low, UInt32 high)
+ {
+ if (low >= high)
+ throw new ArgumentOutOfRangeException(nameof(high), $"{nameof(high)} ({high}) must be higher than {nameof(low)} ({low}).");
+
+ return CreateInclusive(low, (UInt32)(high - 1));
+ }
+
+
+ /// <summary>
+ /// Creates a <see cref="UniformUInt32" /> with an exclusive lower bound. Should not
+ /// be used directly; instead, use <see cref="Uniform.NewInclusive(UInt32, UInt32)" />.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<UInt32> CreateInclusive(UInt32 low, UInt32 high)
+ {
+ if (low > high)
+ throw new ArgumentOutOfRangeException(nameof(high), $"{nameof(high)} ({high}) must be higher than or equal to {nameof(low)} ({low}).");
+
+ var unsignedMax = UInt32.MaxValue;
+ var range = unchecked((UInt32)(high - low + 1));
+ var intsToReject = range == 0 ? 0 : (unsignedMax - range + 1) % range;
+
+ return new UniformInt<UInt32>(low, range, (UInt32)intsToReject);
+ }
+
+
+ /// <summary>
+ /// Creates a <see cref="UniformUInt64" /> with an exclusive upper bound. Should not
+ /// be used directly; instead, use <see cref="Uniform.New(UInt64, UInt64)" />.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<UInt64> Create(UInt64 low, UInt64 high)
+ {
+ if (low >= high)
+ throw new ArgumentOutOfRangeException(nameof(high), $"{nameof(high)} ({high}) must be higher than {nameof(low)} ({low}).");
+
+ return CreateInclusive(low, (UInt64)(high - 1));
+ }
+
+
+ /// <summary>
+ /// Creates a <see cref="UniformUInt64" /> with an exclusive lower bound. Should not
+ /// be used directly; instead, use <see cref="Uniform.NewInclusive(UInt64, UInt64)" />.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<UInt64> CreateInclusive(UInt64 low, UInt64 high)
+ {
+ if (low > high)
+ throw new ArgumentOutOfRangeException(nameof(high), $"{nameof(high)} ({high}) must be higher than or equal to {nameof(low)} ({low}).");
+
+ var unsignedMax = UInt64.MaxValue;
+ var range = unchecked((UInt64)(high - low + 1));
+ var intsToReject = range == 0 ? 0 : (unsignedMax - range + 1) % range;
+
+ return new UniformInt<UInt64>(low, range, (UInt64)intsToReject);
+ }
+
+ }
+
+ /// <summary>
+ /// Implements a Uniform <see cref="IDistribution{TResult}"/> for integral types such as <see cref="Int32" /> and <see cref="UInt64" />.
+ /// Use of any other type results in a runtime exception.
+ /// </summary>
+ public readonly struct UniformInt<T> : IPortableDistribution<T>
+ // We're extremely restrictive here to discourage people from trying to use unsupported types for T
+ where T : struct, IComparable, IComparable<T>, IConvertible, IEquatable<T>, IFormattable
+ {
+ private readonly Number<T> _low;
+ private readonly UInt64 _range;
+ private readonly UInt64 _zone;
+
+ internal UniformInt(Number<T> low, UInt64 range, UInt64 zone)
+ {
+ _low = low;
+ _range = range;
+ _zone = zone;
+ }
+
+ /// <inheritdoc />
+ public T Sample<TRng>(TRng rng) where TRng : notnull, IRng
+ {
+ if (typeof(T) == typeof(Int32))
+ {
+ var unsigned = rng.NextUInt32();
+ if (_range == 0) // 0 is a special case where we sample the entire range.
+ return unchecked(Number.Convert<UInt32, T>(unsigned));
+
+ var zone = UInt32.MaxValue - _zone;
+
+ while (unsigned > zone)
+ {
+ unsigned = rng.NextUInt32();
+ }
+
+ return unchecked(Number.Convert<UInt32, T>(unsigned % (UInt32)_range) + _low);
+ }
+ else
+ {
+ var unsigned = rng.NextUInt64();
+ if (_range == 0) // 0 is a special case where we sample the entire range.
+ return Number.Convert<UInt64, T>(unsigned);
+
+ var zone = UInt64.MaxValue - _zone;
+
+ while (unsigned > zone)
+ {
+ unsigned = rng.NextUInt64();
+ }
+
+ return unchecked(Number.Convert<UInt64, T>(unsigned % _range) + _low);
+ }
+ }
+
+ /// <inheritdoc />
+ public Boolean TrySample<TRng>(TRng rng, out T result) where TRng : notnull, IRng
+ {
+ var unsigned = rng.NextUInt64();
+ if (_range == 0) // 0 is a special case where we sample the entire range.
+ {
+ result = Number.Convert<UInt64, T>(unsigned);
+ return true;
+ }
+
+ var zone = UInt64.MaxValue - _zone;
+
+ if (unsigned > zone)
+ {
+ result = default;
+ return false;
+ }
+
+ result = unchecked(Number.Convert<UInt64, T>(unsigned % _range) + _low);
+ return true;
+ }
+ }
/// <summary>
/// A uniform distribution of type <see cref="SByte" />.
M src/RandN/Distributions/UniformInt.tt +125 -0
@@ 16,10 16,135 @@ var types = new (Type type, Type unsigne
};
#>
using System;
+using Genumerics;
/*** This file is auto generated - any changes made here will be lost. ***/
namespace RandN.Distributions
{
+ internal static class UniformInt
+ {
+<# foreach (var param in types)
+{
+ String type = param.type.Name;
+ String unsigned = param.unsigned.Name;
+ String ularge = param.ularge.Name;
+#>
+
+ /// <summary>
+ /// Creates a <see cref="Uniform<#= type #>" /> with an exclusive upper bound. Should not
+ /// be used directly; instead, use <see cref="Uniform.New(<#= type #>, <#= type #>)" />.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than or equal to <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<<#= type #>> Create(<#= type #> low, <#= type #> high)
+ {
+ if (low >= high)
+ throw new ArgumentOutOfRangeException(nameof(high), $"{nameof(high)} ({high}) must be higher than {nameof(low)} ({low}).");
+
+ return CreateInclusive(low, (<#= type #>)(high - 1));
+ }
+
+
+ /// <summary>
+ /// Creates a <see cref="Uniform<#= type #>" /> with an exclusive lower bound. Should not
+ /// be used directly; instead, use <see cref="Uniform.NewInclusive(<#= type #>, <#= type #>)" />.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Thrown when <paramref name="low"/> is greater than <paramref name="high"/>.
+ /// </exception>
+ public static UniformInt<<#= type #>> CreateInclusive(<#= type #> low, <#= type #> high)
+ {
+ if (low > high)
+ throw new ArgumentOutOfRangeException(nameof(high), $"{nameof(high)} ({high}) must be higher than or equal to {nameof(low)} ({low}).");
+
+ var unsignedMax = <#= ularge #>.MaxValue;
+ var range = unchecked((<#= ularge #>)(high - low + 1));
+ var intsToReject = range == 0 ? 0 : (unsignedMax - range + 1) % range;
+
+ return new UniformInt<<#= type #>>(low, range, (<#= unsigned #>)intsToReject);
+ }
+<#
+}
+#>
+ }
+
+ /// <summary>
+ /// Implements a Uniform <see cref="IDistribution{TResult}"/> for integral types such as <see cref="Int32" /> and <see cref="UInt64" />.
+ /// Use of any other type results in a runtime exception.
+ /// </summary>
+ public readonly struct UniformInt<T> : IPortableDistribution<T>
+ // We're extremely restrictive here to discourage people from trying to use unsupported types for T
+ where T : struct, IComparable, IComparable<T>, IConvertible, IEquatable<T>, IFormattable
+ {
+ private readonly Number<T> _low;
+ private readonly UInt64 _range;
+ private readonly UInt64 _zone;
+
+ internal UniformInt(Number<T> low, UInt64 range, UInt64 zone)
+ {
+ _low = low;
+ _range = range;
+ _zone = zone;
+ }
+
+ /// <inheritdoc />
+ public T Sample<TRng>(TRng rng) where TRng : notnull, IRng
+ {
+ if (typeof(T) == typeof(Int32))
+ {
+ var unsigned = rng.NextUInt32();
+ if (_range == 0) // 0 is a special case where we sample the entire range.
+ return Number.Convert<UInt32, T>(unsigned);
+
+ var zone = UInt32.MaxValue - _zone;
+
+ while (unsigned > zone)
+ {
+ unsigned = rng.NextUInt32();
+ }
+
+ return unchecked(Number.Convert<UInt32, T>(unsigned % (UInt32)_range) + _low);
+ }
+ else
+ {
+ var unsigned = rng.NextUInt64();
+ if (_range == 0) // 0 is a special case where we sample the entire range.
+ return Number.Convert<UInt64, T>(unsigned);
+
+ var zone = UInt64.MaxValue - _zone;
+
+ while (unsigned > zone)
+ {
+ unsigned = rng.NextUInt64();
+ }
+
+ return unchecked(Number.Convert<UInt64, T>(unsigned % _range) + _low);
+ }
+ }
+
+ /// <inheritdoc />
+ public Boolean TrySample<TRng>(TRng rng, out T result) where TRng : notnull, IRng
+ {
+ var unsigned = rng.NextUInt64();
+ if (_range == 0) // 0 is a special case where we sample the entire range.
+ {
+ result = Number.Convert<UInt64, T>(unsigned);
+ return true;
+ }
+
+ var zone = UInt64.MaxValue - _zone;
+
+ if (unsigned > zone)
+ {
+ result = default;
+ return false;
+ }
+
+ result = unchecked(Number.Convert<UInt64, T>(unsigned % _range) + _low);
+ return true;
+ }
+ }
<#
foreach (var tuple in types)
{
M src/RandN/RandN.csproj +1 -0
@@ 57,6 57,7 @@
<PackageReference Include="NullGuard.Fody" Version="3.0.0" />
<PackageReference Include="RandN.Core" Version="0.1.0" />
<ProjectReference Include="..\Core\Core.csproj" />
+ <PackageReference Include="Genumerics" Version="1.0.2" />
</ItemGroup>
<ItemGroup>