Browse Source

Random: clarify ranges, ensure them at the call site #427

netstandard
Christoph Ruegg 10 years ago
parent
commit
8e131b481b
  1. 12
      src/Numerics/Numerics.csproj
  2. 9
      src/Numerics/Properties/Resources.Designer.cs
  3. 3
      src/Numerics/Properties/Resources.resx
  4. 106
      src/Numerics/Random/RandomSource.cs

12
src/Numerics/Numerics.csproj

@ -167,6 +167,11 @@
<Compile Include="LinearRegression\WeightedRegression.cs" /> <Compile Include="LinearRegression\WeightedRegression.cs" />
<Compile Include="LinearRegression\SimpleRegression.cs" /> <Compile Include="LinearRegression\SimpleRegression.cs" />
<Compile Include="LinearRegression\Util.cs" /> <Compile Include="LinearRegression\Util.cs" />
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Providers\LinearAlgebra\Acml\AcmlLinearAlgebraProvider.Complex.cs" /> <Compile Include="Providers\LinearAlgebra\Acml\AcmlLinearAlgebraProvider.Complex.cs" />
<Compile Include="Providers\LinearAlgebra\Acml\AcmlLinearAlgebraProvider.Complex32.cs" /> <Compile Include="Providers\LinearAlgebra\Acml\AcmlLinearAlgebraProvider.Complex32.cs" />
<Compile Include="Providers\LinearAlgebra\Acml\AcmlLinearAlgebraProvider.Double.cs" /> <Compile Include="Providers\LinearAlgebra\Acml\AcmlLinearAlgebraProvider.Double.cs" />
@ -428,11 +433,6 @@
<Compile Include="Interpolation\SplineBoundaryCondition.cs" /> <Compile Include="Interpolation\SplineBoundaryCondition.cs" />
<Compile Include="Precision.cs" /> <Compile Include="Precision.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Random\RandomSource.cs" /> <Compile Include="Random\RandomSource.cs" />
<Compile Include="Random\Mcg31m1.cs" /> <Compile Include="Random\Mcg31m1.cs" />
<Compile Include="Random\Mcg59.cs" /> <Compile Include="Random\Mcg59.cs" />
@ -472,8 +472,8 @@
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="Properties\Resources.resx"> <EmbeddedResource Include="Properties\Resources.resx">
<Generator>PublicResXFileCodeGenerator</Generator> <Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType> <SubType>Designer</SubType>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource> </EmbeddedResource>
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

9
src/Numerics/Properties/Resources.Designer.cs

@ -314,6 +314,15 @@ namespace MathNet.Numerics.Properties {
} }
} }
/// <summary>
/// Looks up a localized string similar to In the specified range, the exclusive maximum must be greater than the inclusive minimum..
/// </summary>
public static string ArgumentMaxExclusiveMustBeLargerThanMinInclusive {
get {
return ResourceManager.GetString("ArgumentMaxExclusiveMustBeLargerThanMinInclusive", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to In the specified range, the minimum is greater than maximum.. /// Looks up a localized string similar to In the specified range, the minimum is greater than maximum..
/// </summary> /// </summary>

3
src/Numerics/Properties/Resources.resx

@ -282,6 +282,9 @@
<data name="ArgumentMinValueGreaterThanMaxValue" xml:space="preserve"> <data name="ArgumentMinValueGreaterThanMaxValue" xml:space="preserve">
<value>In the specified range, the minimum is greater than maximum.</value> <value>In the specified range, the minimum is greater than maximum.</value>
</data> </data>
<data name="ArgumentMaxExclusiveMustBeLargerThanMinInclusive" xml:space="preserve">
<value>In the specified range, the exclusive maximum must be greater than the inclusive minimum.</value>
</data>
<data name="ArgumentUpperBoundMustBeLargerThanOrEqualToLowerBound" xml:space="preserve"> <data name="ArgumentUpperBoundMustBeLargerThanOrEqualToLowerBound" xml:space="preserve">
<value>The upper bound must be at least as large as the lower bound.</value> <value>The upper bound must be at least as large as the lower bound.</value>
</data> </data>

106
src/Numerics/Random/RandomSource.cs

@ -3,7 +3,7 @@
// http://numerics.mathdotnet.com // http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics // http://github.com/mathnet/mathnet-numerics
// //
// Copyright (c) 2009-2015 Math.NET // Copyright (c) 2009-2016 Math.NET
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
@ -133,28 +133,39 @@ namespace MathNet.Numerics.Random
return DoSampleInteger(); return DoSampleInteger();
} }
} }
else
return DoSampleInteger(); {
return DoSampleInteger();
}
} }
/// <summary> /// <summary>
/// Returns a random number less then a specified maximum. /// Returns a random number less then a specified maximum.
/// </summary> /// </summary>
/// <param name="maxExclusive">The exclusive upper bound of the random number returned.</param> /// <param name="maxExclusive">The exclusive upper bound of the random number returned. Range: maxExclusive ≥ 1.</param>
/// <returns>A 32-bit signed integer less than <paramref name="maxExclusive"/>.</returns> /// <returns>A 32-bit signed integer less than <paramref name="maxExclusive"/>.</returns>
/// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="maxExclusive"/> is negative. </exception> /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="maxExclusive"/> is zero or negative.</exception>
public sealed override int Next(int maxExclusive) public sealed override int Next(int maxExclusive)
{ {
// Invalid case: Zero and less are not valid use cases.
if (maxExclusive <= 0) if (maxExclusive <= 0)
{ {
throw new ArgumentException(Resources.ArgumentMustBePositive); throw new ArgumentException(Resources.ArgumentMustBePositive);
} }
// Fast case: Only zero is allowed to be returned. No sampling is needed.
if (maxExclusive == 1)
{
return 0;
}
// Simple case: standard range
if (maxExclusive == int.MaxValue) if (maxExclusive == int.MaxValue)
{ {
return Next(); return Next();
} }
// Sample with 1 < maxExclusive < int.MaxValue
if (_threadSafe) if (_threadSafe)
{ {
lock (_lock) lock (_lock)
@ -162,28 +173,39 @@ namespace MathNet.Numerics.Random
return DoSampleInteger(maxExclusive); return DoSampleInteger(maxExclusive);
} }
} }
else
return DoSampleInteger(maxExclusive); {
return DoSampleInteger(maxExclusive);
}
} }
/// <summary> /// <summary>
/// Returns a random number within a specified range. /// Returns a random number within a specified range.
/// </summary> /// </summary>
/// <param name="minInclusive">The inclusive lower bound of the random number returned.</param> /// <param name="minInclusive">The inclusive lower bound of the random number returned.</param>
/// <param name="maxExclusive">The exclusive upper bound of the random number returned. <paramref name="maxExclusive"/> must be greater than or equal to <paramref name="minInclusive"/>.</param> /// <param name="maxExclusive">The exclusive upper bound of the random number returned. Range: maxExclusive > minExclusive.</param>
/// <returns> /// <returns>
/// A 32-bit signed integer greater than or equal to <paramref name="minInclusive"/> and less than <paramref name="maxExclusive"/>; that is, the range of return values includes <paramref name="minInclusive"/> but not <paramref name="maxExclusive"/>. If <paramref name="minInclusive"/> equals <paramref name="maxExclusive"/>, <paramref name="minInclusive"/> is returned. /// A 32-bit signed integer greater than or equal to <paramref name="minInclusive"/> and less than <paramref name="maxExclusive"/>; that is, the range of return values includes <paramref name="minInclusive"/> but not <paramref name="maxExclusive"/>. If <paramref name="minInclusive"/> equals <paramref name="maxExclusive"/>, <paramref name="minInclusive"/> is returned.
/// </returns> /// </returns>
/// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="minInclusive"/> is greater than <paramref name="maxExclusive"/>. </exception> /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="minInclusive"/> is greater than <paramref name="maxExclusive"/>. </exception>
public sealed override int Next(int minInclusive, int maxExclusive) public sealed override int Next(int minInclusive, int maxExclusive)
{ {
if (minInclusive > maxExclusive) // Invalid case: empty range.
if (minInclusive >= maxExclusive)
{ {
throw new ArgumentException(Resources.ArgumentMinValueGreaterThanMaxValue); throw new ArgumentException(Resources.ArgumentMaxExclusiveMustBeLargerThanMinInclusive);
}
// Fast case: Only minInclusive is allowed to be returned. No sampling is needed.
if (maxExclusive == minInclusive + 1)
{
return minInclusive;
} }
// Simple case: simple range
if (minInclusive == 0) if (minInclusive == 0)
{ {
// Simple case: standard range
if (maxExclusive == int.MaxValue) if (maxExclusive == int.MaxValue)
{ {
return Next(); return Next();
@ -192,6 +214,7 @@ namespace MathNet.Numerics.Random
return Next(maxExclusive); return Next(maxExclusive);
} }
// Sample with minInclusive + 1 < maxExclusive
if (_threadSafe) if (_threadSafe)
{ {
lock (_lock) lock (_lock)
@ -199,8 +222,10 @@ namespace MathNet.Numerics.Random
return DoSampleInteger(minInclusive, maxExclusive); return DoSampleInteger(minInclusive, maxExclusive);
} }
} }
else
return DoSampleInteger(minInclusive, maxExclusive); {
return DoSampleInteger(minInclusive, maxExclusive);
}
} }
/// <summary> /// <summary>
@ -243,15 +268,30 @@ namespace MathNet.Numerics.Random
/// Fills an array with random numbers within a specified range. /// Fills an array with random numbers within a specified range.
/// </summary> /// </summary>
/// <param name="values">The array to fill with random values.</param> /// <param name="values">The array to fill with random values.</param>
/// <param name="maxExclusive">The exclusive upper bound of the random number returned.</param> /// <param name="maxExclusive">The exclusive upper bound of the random number returned. Range: maxExclusive ≥ 1.</param>
public void NextInt32s(int[] values, int maxExclusive) public void NextInt32s(int[] values, int maxExclusive)
{ {
// Invalid case: Zero and less are not valid use cases.
if (maxExclusive <= 0)
{
throw new ArgumentException(Resources.ArgumentMustBePositive);
}
// Fast case: Only zero is allowed to be returned. No sampling is needed.
if (maxExclusive == 1)
{
Array.Clear(values, 0, values.Length);
return;
}
// Simple case: standard range
if (maxExclusive == int.MaxValue) if (maxExclusive == int.MaxValue)
{ {
NextInt32s(values); NextInt32s(values);
return; return;
} }
// Sample with 1 < maxExclusive < int.MaxValue
if (_threadSafe) if (_threadSafe)
{ {
lock (_lock) lock (_lock)
@ -271,27 +311,46 @@ namespace MathNet.Numerics.Random
} }
} }
/// <summary>
/// Returns an array with random 32-bit signed integers within the specified range.
/// </summary>
/// <param name="count">The size of the array to fill.</param>
/// <param name="maxExclusive">The exclusive upper bound of the random number returned. Range: maxExclusive ≥ 1.</param>
public int[] NextInt32s(int count, int maxExclusive)
{
var values = new int[count];
NextInt32s(values, maxExclusive);
return values;
}
/// <summary> /// <summary>
/// Fills an array with random numbers within a specified range. /// Fills an array with random numbers within a specified range.
/// </summary> /// </summary>
/// <param name="values">The array to fill with random values.</param> /// <param name="values">The array to fill with random values.</param>
/// <param name="minInclusive">The inclusive lower bound of the random number returned.</param> /// <param name="minInclusive">The inclusive lower bound of the random number returned.</param>
/// <param name="maxExclusive">The exclusive upper bound of the random number returned. <paramref name="maxExclusive"/> must be greater than or equal to <paramref name="minInclusive"/>.</param> /// <param name="maxExclusive">The exclusive upper bound of the random number returned. Range: maxExclusive > minExclusive.</param>
public void NextInt32s(int[] values, int minInclusive, int maxExclusive) public void NextInt32s(int[] values, int minInclusive, int maxExclusive)
{ {
if (minInclusive > maxExclusive) // Invalid case: empty range.
if (minInclusive >= maxExclusive)
{ {
throw new ArgumentException(Resources.ArgumentMinValueGreaterThanMaxValue); throw new ArgumentException(Resources.ArgumentMaxExclusiveMustBeLargerThanMinInclusive);
} }
if (maxExclusive == int.MaxValue && minInclusive == 0) // Fast case: Only minInclusive is allowed to be returned. No sampling is needed.
if (maxExclusive == minInclusive + 1)
{ {
NextInt32s(values); for (var i = 0; i < values.Length; i++)
{
values[i] = minInclusive;
}
return; return;
} }
// Simple case: simple range
if (minInclusive == 0) if (minInclusive == 0)
{ {
// Simple case: standard range
if (maxExclusive == int.MaxValue) if (maxExclusive == int.MaxValue)
{ {
NextInt32s(values); NextInt32s(values);
@ -302,6 +361,7 @@ namespace MathNet.Numerics.Random
return; return;
} }
// Sample with minInclusive + 1 < maxExclusive
if (_threadSafe) if (_threadSafe)
{ {
lock (_lock) lock (_lock)
@ -326,7 +386,7 @@ namespace MathNet.Numerics.Random
/// </summary> /// </summary>
/// <param name="count">The size of the array to fill.</param> /// <param name="count">The size of the array to fill.</param>
/// <param name="minInclusive">The inclusive lower bound of the random number returned.</param> /// <param name="minInclusive">The inclusive lower bound of the random number returned.</param>
/// <param name="maxExclusive">The exclusive upper bound of the random number returned. <paramref name="maxExclusive"/> must be greater than or equal to <paramref name="minInclusive"/>.</param> /// <param name="maxExclusive">The exclusive upper bound of the random number returned. Range: maxExclusive > minExclusive.</param>
public int[] NextInt32s(int count, int minInclusive, int maxExclusive) public int[] NextInt32s(int count, int minInclusive, int maxExclusive)
{ {
var values = new int[count]; var values = new int[count];
@ -359,7 +419,7 @@ namespace MathNet.Numerics.Random
/// Returns an infinite sequence of random numbers within a specified range. /// Returns an infinite sequence of random numbers within a specified range.
/// </summary> /// </summary>
/// <param name="minInclusive">The inclusive lower bound of the random number returned.</param> /// <param name="minInclusive">The inclusive lower bound of the random number returned.</param>
/// <param name="maxExclusive">The exclusive upper bound of the random number returned. <paramref name="maxExclusive"/> must be greater than or equal to <paramref name="minInclusive"/>.</param> /// <param name="maxExclusive">The exclusive upper bound of the random number returned. Range: maxExclusive > minExclusive.</param>
public IEnumerable<int> NextInt32Sequence(int minInclusive, int maxExclusive) public IEnumerable<int> NextInt32Sequence(int minInclusive, int maxExclusive)
{ {
if (minInclusive > maxExclusive) if (minInclusive > maxExclusive)
@ -461,6 +521,7 @@ namespace MathNet.Numerics.Random
{ {
return 0; return 0;
} }
var bytes = new byte[4]; var bytes = new byte[4];
DoSampleBytes(bytes); DoSampleBytes(bytes);
@ -484,6 +545,7 @@ namespace MathNet.Numerics.Random
{ {
return 0; return 0;
} }
var bytes = new byte[8]; var bytes = new byte[8];
DoSampleBytes(bytes); DoSampleBytes(bytes);
@ -498,7 +560,7 @@ namespace MathNet.Numerics.Random
/// <summary> /// <summary>
/// Returns a random 32-bit signed integer within the specified range. /// Returns a random 32-bit signed integer within the specified range.
/// </summary> /// </summary>
/// <param name="maxExclusive">The exclusive upper bound of the random number returned.</param> /// <param name="maxExclusive">The exclusive upper bound of the random number returned. Range: maxExclusive ≥ 1.</param>
protected virtual int DoSampleInteger(int maxExclusive) protected virtual int DoSampleInteger(int maxExclusive)
{ {
// Fast case: Only a single number is allowed to be returned // Fast case: Only a single number is allowed to be returned
@ -535,7 +597,7 @@ namespace MathNet.Numerics.Random
/// Returns a random 32-bit signed integer within the specified range. /// Returns a random 32-bit signed integer within the specified range.
/// </summary> /// </summary>
/// <param name="minInclusive">The inclusive lower bound of the random number returned.</param> /// <param name="minInclusive">The inclusive lower bound of the random number returned.</param>
/// <param name="maxExclusive">The exclusive upper bound of the random number returned. <paramref name="maxExclusive"/> must be greater than or equal to <paramref name="minInclusive"/>.</param> /// <param name="maxExclusive">The exclusive upper bound of the random number returned. Range: maxExclusive > minExclusive.</param>
protected virtual int DoSampleInteger(int minInclusive, int maxExclusive) protected virtual int DoSampleInteger(int minInclusive, int maxExclusive)
{ {
return DoSampleInteger(maxExclusive - minInclusive) + minInclusive; return DoSampleInteger(maxExclusive - minInclusive) + minInclusive;

Loading…
Cancel
Save