MPIR 2.6.0 section 9 - random state init/seed/clear/generate_ui

This commit is contained in:
Alex Dyachenko 2014-04-29 23:06:30 -04:00
parent e884839eec
commit e22246209f
7 changed files with 432 additions and 13 deletions

View File

@ -94,18 +94,45 @@
</Otherwise>
</Choose>
<ItemGroup>
<Compile Include="..\..\..\mpir.net\mpir.net-tests\HugeIntTests\Arithmetic.cs" />
<Compile Include="..\..\..\mpir.net\mpir.net-tests\HugeIntTests\Assignment.cs" />
<Compile Include="..\..\..\mpir.net\mpir.net-tests\HugeIntTests\Bitwise.cs" />
<Compile Include="..\..\..\mpir.net\mpir.net-tests\HugeIntTests\Conversions.cs" />
<Compile Include="..\..\..\mpir.net\mpir.net-tests\HugeIntTests\Comparisons.cs" />
<Compile Include="..\..\..\mpir.net\mpir.net-tests\HugeIntTests\ExpressionTests.cs" />
<Compile Include="..\..\..\mpir.net\mpir.net-tests\HugeIntTests\IO.cs" />
<Compile Include="..\..\..\mpir.net\mpir.net-tests\HugeIntTests\Math.cs" />
<Compile Include="..\..\..\mpir.net\mpir.net-tests\HugeIntTests\XmlCommentsTests.cs" />
<Compile Include="..\..\..\mpir.net\mpir.net-tests\Utilities\Accessors.cs" />
<Compile Include="..\..\..\mpir.net\mpir.net-tests\HugeIntTests\ConstructionAndDisposal.cs" />
<Compile Include="..\..\..\mpir.net\mpir.net-tests\Properties\AssemblyInfo.cs" />
<Compile Include="..\..\..\mpir.net\mpir.net-tests\HugeIntTests\Arithmetic.cs">
<Link>HugeIntTests\Arithmetic.cs</Link>
</Compile>
<Compile Include="..\..\..\mpir.net\mpir.net-tests\HugeIntTests\Assignment.cs">
<Link>HugeIntTests\Assignment.cs</Link>
</Compile>
<Compile Include="..\..\..\mpir.net\mpir.net-tests\HugeIntTests\Bitwise.cs">
<Link>HugeIntTests\Bitwise.cs</Link>
</Compile>
<Compile Include="..\..\..\mpir.net\mpir.net-tests\HugeIntTests\Conversions.cs">
<Link>HugeIntTests\Conversions.cs</Link>
</Compile>
<Compile Include="..\..\..\mpir.net\mpir.net-tests\HugeIntTests\Comparisons.cs">
<Link>HugeIntTests\Comparisons.cs</Link>
</Compile>
<Compile Include="..\..\..\mpir.net\mpir.net-tests\HugeIntTests\ExpressionTests.cs">
<Link>HugeIntTests\ExpressionTests.cs</Link>
</Compile>
<Compile Include="..\..\..\mpir.net\mpir.net-tests\HugeIntTests\IO.cs">
<Link>HugeIntTests\IO.cs</Link>
</Compile>
<Compile Include="..\..\..\mpir.net\mpir.net-tests\HugeIntTests\Math.cs">
<Link>HugeIntTests\Math.cs</Link>
</Compile>
<Compile Include="..\..\..\mpir.net\mpir.net-tests\HugeIntTests\XmlCommentsTests.cs">
<Link>IntegrationTests\XmlCommentsTests.cs</Link>
</Compile>
<Compile Include="..\..\..\mpir.net\mpir.net-tests\RandomTests\Random.cs">
<Link>RandomTests\Random.cs</Link>
</Compile>
<Compile Include="..\..\..\mpir.net\mpir.net-tests\Utilities\Accessors.cs">
<Link>Utilities\Accessors.cs</Link>
</Compile>
<Compile Include="..\..\..\mpir.net\mpir.net-tests\HugeIntTests\ConstructionAndDisposal.cs">
<Link>HugeIntTests\ConstructionAndDisposal.cs</Link>
</Compile>
<Compile Include="..\..\..\mpir.net\mpir.net-tests\Properties\AssemblyInfo.cs">
<Link>Properties\AssemblyInfo.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\mpir.net\mpir.net.vcxproj">
@ -113,6 +140,7 @@
<Name>mpir.net</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<Choose>
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
<ItemGroup>

View File

@ -143,6 +143,7 @@
<ItemGroup>
<ClInclude Include="..\..\..\mpir.net\mpir.net\Common.h" />
<ClInclude Include="..\..\..\mpir.net\mpir.net\HugeInt.h" />
<ClInclude Include="..\..\..\mpir.net\mpir.net\Random.h" />
<ClInclude Include="..\..\..\mpir.net\mpir.net\resource.h" />
<ClInclude Include="..\..\..\mpir.net\mpir.net\Stdafx.h" />
</ItemGroup>
@ -150,6 +151,7 @@
<ClCompile Include="..\..\..\mpir.net\mpir.net\AssemblyInfo.cpp" />
<ClCompile Include="..\..\..\mpir.net\mpir.net\Common.cpp" />
<ClCompile Include="..\..\..\mpir.net\mpir.net\HugeInt.cpp" />
<ClCompile Include="..\..\..\mpir.net\mpir.net\Random.cpp" />
<ClCompile Include="..\..\..\mpir.net\mpir.net\Stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>

View File

@ -27,6 +27,9 @@
<ClInclude Include="..\..\..\mpir.net\mpir.net\Common.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\mpir.net\mpir.net\Random.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\mpir.net\mpir.net\AssemblyInfo.cpp">
@ -41,6 +44,9 @@
<ClCompile Include="..\..\..\mpir.net\mpir.net\Common.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\mpir.net\mpir.net\Random.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Text Include="..\..\..\mpir.net\mpir.net\ReadMe.txt" />

View File

@ -0,0 +1,152 @@
/*
Copyright 2014 Alex Dyachenko
This file is part of the MPIR Library.
The MPIR Library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or (at
your option) any later version.
The MPIR Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the MPIR Library. If not, see http://www.gnu.org/licenses/.
*/
using System;
using System.IO;
using System.Text;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace MPIR.Tests.RandomTests
{
[TestClass]
public class RandomTests
{
private void TestRandom(MpirRandom r, ulong seed, Action<MpirRandom> assert)
{
MpirRandom copy = null;
for (var i = 0; i < 6; i++)
{
switch (i)
{
case 0:
case 1:
case 5:
r.Seed(seed);
break;
case 2:
using (var s = HugeInt.FromUlong(seed))
r.Seed(s);
break;
case 3:
using (var s = HugeInt.FromUlong(seed))
r.Seed(s);
copy = r.Copy();
break;
case 4:
r.Seed(seed); //r = copy; temporarily disabled copy tests due to MPIR bug
break;
}
assert(r);
}
copy.Dispose();
}
[TestMethod]
public void SeedingMersenneTwister()
{
using (var r = MpirRandom.MersenneTwister())
{
ulong seed = 12345789;
ulong max = 10000000;
ulong bits = 62;
ulong expected1 = 3801341;
ulong expected2 = 747743;
ulong expected3 = 3637762780660169521;
TestRandom(r, seed, x =>
{
Assert.AreEqual(expected1, x.GetRandomLimb(max));
Assert.AreEqual(expected2, x.GetRandomLimb(max));
Assert.AreEqual(expected3, x.GetRandomLimbBits(bits));
});
}
}
[TestMethod]
public void SeedingDefault()
{
using (var r = MpirRandom.Default())
{
ulong seed = 12345789;
ulong max = 10000000;
ulong bits = 62;
ulong expected1 = 3801341;
ulong expected2 = 747743;
ulong expected3 = 3637762780660169521;
TestRandom(r, seed, x =>
{
Assert.AreEqual(expected1, x.GetRandomLimb(max));
Assert.AreEqual(expected2, x.GetRandomLimb(max));
Assert.AreEqual(expected3, x.GetRandomLimbBits(bits));
});
}
}
[TestMethod]
public void SeedingLCSize()
{
using (var r = MpirRandom.LinearCongruential(128))
{
ulong seed = 12345789;
ulong max = 10000000;
ulong bits = 62;
ulong expected1 = 8017343;
ulong expected2 = 2122346;
ulong expected3 = 1653945017297503111;
TestRandom(r, seed, x =>
{
Assert.AreEqual(expected1, x.GetRandomLimb(max));
Assert.AreEqual(expected2, x.GetRandomLimb(max));
Assert.AreEqual(expected3, x.GetRandomLimbBits(bits));
});
}
}
[TestMethod]
public void SeedingLC()
{
using (var a = new HugeInt("5209384572093847098342590872309452304529345409827509283745078"))
using (var r = MpirRandom.LinearCongruential(a, 98570948725939831, 256))
{
ulong seed = 12345789;
ulong max = 10000000;
ulong bits = 62;
ulong expected1 = 6524662;
ulong expected2 = 5428780;
ulong expected3 = 4189233241027086562;
TestRandom(r, seed, x =>
{
Assert.AreEqual(expected1, x.GetRandomLimb(max));
Assert.AreEqual(expected2, x.GetRandomLimb(max));
Assert.AreEqual(expected3, x.GetRandomLimbBits(bits));
});
}
}
}
}

View File

@ -1436,7 +1436,7 @@ namespace MPIR
void DeallocateStruct()
{
mpz_clear(_value);
(*__gmp_free_func)(_value, 0);
(*__gmp_free_func)(_value, sizeof(__mpz_struct));
_value = nullptr;
}
void FromString(String^ value, int base);

View File

@ -0,0 +1,26 @@
/*
Copyright 2014 Alex Dyachenko
This file is part of the MPIR Library.
The MPIR Library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or (at
your option) any later version.
The MPIR Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the MPIR Library. If not, see http://www.gnu.org/licenses/.
*/
#include "Stdafx.h"
#include "Random.h"
namespace MPIR
{
};

205
mpir.net/mpir.net/Random.h Normal file
View File

@ -0,0 +1,205 @@
/*
Copyright 2014 Alex Dyachenko
This file is part of the MPIR Library.
The MPIR Library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or (at
your option) any later version.
The MPIR Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the MPIR Library. If not, see http://www.gnu.org/licenses/.
*/
#pragma once
using namespace System;
namespace MPIR
{
/// <summary>
/// This class encapsulates a random number generator algorithm and state
/// </summary>
public ref class MpirRandom
{
internal:
//fields
gmp_randstate_ptr _value;
#pragma region Construction and disposal
private:
MpirRandom()
{
_value = (gmp_randstate_ptr)((*__gmp_allocate_func)(sizeof(__gmp_randstate_struct)));
}
public:
//creating a destructor in C++ implements IDisposable.
/// <summary>
/// Frees all memory allocated by the instance.
/// <para>To minimize memory footprint, MPIR objects should be disposed of when no longer used, instead of relying on the garbage collector to free the memory.
/// </para></summary>
~MpirRandom() { this->!MpirRandom(); }
/// <summary>
/// Frees all memory allocated by the instance.
/// <para>To minimize memory footprint, MPIR objects should be disposed of when no longer used, instead of relying on the garbage collector to free the memory.
/// </para></summary>
!MpirRandom()
{
if(_value != 0)
{
gmp_randclear(_value);
(*__gmp_free_func)(_value, sizeof(__gmp_randstate_struct));
_value = nullptr;
}
}
#pragma endregion
#pragma region Initialization factory methods
/// <summary>
/// Creates a new random generator with a copy of the algorithm and state from this instance
/// </summary>
/// <returns>The newly initialized instance</returns>
MpirRandom^ Copy()
{
auto result = gcnew MpirRandom();
gmp_randinit_set(result->_value, _value);
return result;
}
/// <summary>
/// Creates a new random generator with the default algorithm.
/// <para>This will be a compromise between speed and randomness, and is recommended for applications with no special requirements.
/// </para>Currently Mersenne Twister is the default algorithm.
/// </summary>
/// <returns>The newly initialized instance</returns>
static MpirRandom^ Default()
{
auto result = gcnew MpirRandom();
gmp_randinit_default(result->_value);
return result;
}
/// <summary>
/// Creates a new random generator with the Mersenne Twister algorithm. This algorithm is fast and has good randomness properties.
/// </summary>
/// <returns>The newly initialized instance</returns>
static MpirRandom^ MersenneTwister()
{
auto result = gcnew MpirRandom();
gmp_randinit_mt(result->_value);
return result;
}
/// <summary>
/// Creates a new random generator with a linear congruential algorithm X = (aX + c) mod 2^m.
/// <para>The low bits of X in this algorithm are not very random. The least significant bit will have
/// a period no more than 2, and the second bit no more than 4, etc. For this reason only the
/// high half of each X is actually used.
/// </para>When a random number of more than m/2 bits is to be generated, multiple iterations
/// of the recurrence are used and the results concatenated.
/// </summary>
/// <param name="a">The multiplier in the algorithm's formula X = (aX + c) mod 2^m</param>
/// <param name="c">The addend in the algorithm's formula X = (aX + c) mod 2^m</param>
/// <param name="m">The power of 2 for the divisor in the algorithm's formula X = (aX + c) mod 2^m</param>
/// <returns>The newly initialized instance</returns>
static MpirRandom^ LinearCongruential(HugeInt^ a, mpir_ui c, mp_bitcnt_t m)
{
auto result = gcnew MpirRandom();
gmp_randinit_lc_2exp(result->_value, a->_value, c, m);
return result;
}
/// <summary>
/// Creates a new random generator with a linear congruential algorithm X = (aX + c) mod 2^m.
/// <para>a, c and m are selected from a table, chosen so that size bits (or more) of each X will be used, i.e. m/2 >= size.
/// </para>The maximum size currently supported is 128.
/// </summary>
/// <param name="size">The number of high bits that should be used from each iteration of the algorithm. The current maximum is 128.</param>
/// <returns>The newly initialized instance</returns>
static MpirRandom^ LinearCongruential(mp_bitcnt_t size)
{
auto result = gcnew MpirRandom();
if(gmp_randinit_lc_2exp_size(result->_value, size) == 0)
{
result->!MpirRandom();
throw gcnew ArgumentException("Invalid size", "size");
}
return result;
}
#pragma endregion
#pragma region Seeding
/// <summary>
/// Sets an initial seed value into the random number generator.
/// </summary>
/// <param name="seed">The seed value</param>
/// <remarks>
/// The size of a seed determines how many different sequences of random numbers it's
/// possible to generate. The "quality" of the seed is the randomness of a given seed compared
/// to the previous seed used, and this affects the randomness of separate number sequences. The
/// method for choosing a seed is critical if the generated numbers are to be used for important
/// applications, such as generating cryptographic keys.
/// <para>Traditionally the system time has been used to seed, but care needs to be taken with this.
/// If an application seeds often and the resolution of the system clock is low, then the same
/// sequence of numbers might be repeated. Also, the system time is quite easy to guess, so if
/// unpredictability is required then it should definitely not be the only source for the seed value.
/// </para>On some systems there's a special device '/dev/random' which provides random data better
/// suited for use as a seed.
/// </remarks>
void Seed(mpir_ui seed) { gmp_randseed_ui(_value, seed); }
/// <summary>
/// Sets an initial seed value into the random number generator.
/// </summary>
/// <param name="seed">The seed value</param>
/// <remarks>
/// The size of a seed determines how many different sequences of random numbers it's
/// possible to generate. The "quality" of the seed is the randomness of a given seed compared
/// to the previous seed used, and this affects the randomness of separate number sequences. The
/// method for choosing a seed is critical if the generated numbers are to be used for important
/// applications, such as generating cryptographic keys.
/// <para>Traditionally the system time has been used to seed, but care needs to be taken with this.
/// If an application seeds often and the resolution of the system clock is low, then the same
/// sequence of numbers might be repeated. Also, the system time is quite easy to guess, so if
/// unpredictability is required then it should definitely not be the only source for the seed value.
/// </para>On some systems there's a special device '/dev/random' which provides random data better
/// suited for use as a seed.
/// </remarks>
void Seed(HugeInt^ seed) { gmp_randseed(_value, seed->_value); }
#pragma endergion
#pragma region Random Limb
/// <summary>
/// Generates a uniformly distributed random number of <paramref name="bitCount"/> bits, i.e. in the range 0 to 2^<paramref name="bitCount"/>-1 inclusive.
/// </summary>
/// <param name="bitCount">The number of random bits to generate. Must be less than or equal to the number of bits in a limb.</param>
/// <returns>The newly generated number</returns>
mpir_ui GetRandomLimbBits(mpir_ui bitCount) { return gmp_urandomb_ui(_value, bitCount); }
/// <summary>
/// Generates a uniformly distributed random number in the range 0 to <paramref name="max"/>-1 inclusive.
/// </summary>
/// <param name="max">The exclusive upper bound for the random number</param>
/// <returns>The newly generated number</returns>
mpir_ui GetRandomLimb(mpir_ui max) { return gmp_urandomm_ui(_value, max); }
#pragma endergion
};
};