Auto-allocating version of the Export. Completed MPIR 2.6.0 section 5.14.

This commit is contained in:
Alex Dyachenko 2014-04-28 11:37:09 -04:00
parent fa0939fbd3
commit aa93d2f13a
2 changed files with 98 additions and 7 deletions

View File

@ -210,6 +210,70 @@ namespace MPIR.Tests.HugeIntTests
}
}
}
[TestMethod]
public void ImportExportAllocating()
{
using (var a = new HugeInt("0x10123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"))
using (var b = new HugeInt())
{
foreach (var order in Enum.GetValues(typeof(LimbOrder)).Cast<LimbOrder>())
foreach (var endianness in Enum.GetValues(typeof(Endianness)).Cast<Endianness>())
foreach (var nails in new[] { 0, 5, 10, 16 })
foreach (var size in new[] { 8, 11, 16 })
{
var bytes = a.Export<byte>(size, order, endianness, nails);
var expected = (int)System.Math.Ceiling(193m / (size * 8 - nails));
Assert.AreEqual(expected, bytes.Length / size);
b.SetTo(0);
b.Import(bytes, (ulong)(bytes.Length / size), size, order, endianness, nails);
Assert.AreEqual(a, b);
}
}
}
[TestMethod]
public void ImportExportAllocatingShort()
{
using (var a = new HugeInt("0x10123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"))
using (var b = new HugeInt())
{
foreach (var order in Enum.GetValues(typeof(LimbOrder)).Cast<LimbOrder>())
foreach (var endianness in Enum.GetValues(typeof(Endianness)).Cast<Endianness>())
foreach (var nails in new[] { 0, 5, 10, 16 })
foreach (var size in new[] { 8, 11, 16 })
{
var bytes = a.Export<short>(size, order, endianness, nails);
var expected = (int)System.Math.Ceiling(193m / (size * 8 - nails));
Assert.AreEqual(expected, bytes.Length * 2 / size);
b.SetTo(0);
b.Import(bytes, (ulong)(bytes.Length * 2 / size), size, order, endianness, nails);
Assert.AreEqual(a, b);
}
}
}
[TestMethod]
public void ImportExportAllocatingZero()
{
using (var a = new HugeInt())
using (var b = new HugeInt())
{
var order = LimbOrder.LeastSignificantFirst;
var endianness = Endianness.Native;
var nails = 5;
var size = 4;
var bytes = a.Export<byte>(size, order, endianness, nails);
Assert.AreEqual(0, bytes.Length);
b.SetTo(1);
b.Import(bytes, 0, size, order, endianness, nails);
Assert.AreEqual(a, b);
}
}
//more tests coming here
}
}

View File

@ -1878,6 +1878,12 @@ namespace MPIR
/// <param name="nails">The number of most-significant bits to ignore in each "limb."</param>
generic<typename T> where T : value class void Import(array<T>^ data, size_t limbCount, int bytesPerLimb, LimbOrder limbOrder, Endianness endianness, int nails)
{
if(limbCount == 0)
{
mpz_set_ui(_value, 0);
return;
}
PIN(data);
mpz_import(_value, limbCount, (int)limbOrder, bytesPerLimb, (int)endianness, nails, pinned_data);
}
@ -1889,8 +1895,7 @@ namespace MPIR
/// <typeparam name="T">Type of element in the data array. This must be a value type, but does not need to represent a single limb. Data is interpreted as a flat byte array.</typeparam>
/// <param name="data">Array of binary "limbs" to export to.
/// <para>Elements don't necessarily need to be of the <paramref name="bytesPerLimb"/> size; the data is interpreted as a flat byte array.
/// </para>The total size of the array in bytes must be sufficient for the export.
/// <para>If null, a new array is automatically allocated.</para></param>
/// </para>The total size of the array in bytes must be sufficient for the export.</param>
/// <param name="bytesPerLimb">Number of bytes per "limb."</param>
/// <param name="limbOrder">Specifies the order of the "limbs."</param>
/// <param name="endianness">Specifies the byte order within each "limb."</param>
@ -1900,17 +1905,39 @@ namespace MPIR
/// </para>If the number is zero, then the count returned will be zero and nothing written to the data.</returns>
generic<typename T> where T : value class size_t Export(array<T>^ data, int bytesPerLimb, LimbOrder limbOrder, Endianness endianness, int nails)
{
if(IS_NULL(data))
{
//todo allocate
}
PIN(data);
size_t limbCount;
mpz_export(pinned_data, &limbCount, (int)limbOrder, bytesPerLimb, (int)endianness, nails, _value);
return limbCount;
}
/// <summary>
/// Exports the absolute value of the number to arbitrary words of binary data. An array of type T is allocated for the export.
/// <para>The sign of op is ignored.
/// </para></summary>
/// <typeparam name="T">Type of element in the data array. This must be a value type, but does not need to represent a single limb. Data is interpreted as a flat byte array.</typeparam>
/// <param name="bytesPerLimb">Number of bytes per "limb."</param>
/// <param name="limbOrder">Specifies the order of the "limbs."</param>
/// <param name="endianness">Specifies the byte order within each "limb."</param>
/// <param name="nails">The number of most-significant bits to reserve, and set to zero, in each "limb."</param>
/// <returns>An array of type T containing the exported limb data.
/// <para>If the number is non-zero, then the most significant word produced will be non-zero.
/// </para>If the number is zero, then a zero-length array is returned.</returns>
generic<typename T> where T : value class array<T>^ Export(int bytesPerLimb, LimbOrder limbOrder, Endianness endianness, int nails)
{
if(this->Sign() == 0)
return gcnew array<T>(0);
auto bitsPerLimb = 8 * bytesPerLimb - nails;
auto limbCount = (mpz_sizeinbase(_value, 2) - 1) / bitsPerLimb + 1;
auto arrayCount = (limbCount * bytesPerLimb - 1) / sizeof(T) + 1;
auto data = gcnew array<T>(arrayCount);
PIN(data);
mpz_export(pinned_data, &limbCount, (int)limbOrder, bytesPerLimb, (int)endianness, nails, _value);
return data;
}
internal:
size_t ReadNoWhite(TextReader^ reader, int base, size_t nread);