Skip to content

Commit

Permalink
Implemented Read/Write/Modify limbs methods in MPIR.Net based on the …
Browse files Browse the repository at this point in the history
…new mpz_limbs_xxx functions
  • Loading branch information
Alex Dyachenko committed Jul 11, 2017
1 parent f2ebcaf commit e10eae8
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 0 deletions.
92 changes: 92 additions & 0 deletions mpir.net/mpir.net-tests/HugeIntTests/IO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,98 @@ public void IntGetLimb()
Assert.AreEqual(Platform.Ui(0xA123456789ABCDEFUL, 0x01234567U), a.GetLimb(1));
}
}

[TestMethod]
public void IntReadLimbs()
{
var dest = Enumerable.Repeat(Platform.Ui(0, 0), 8).ToArray();

using (var a = new HugeInt("-0x55533123456789ABCDEF02468ACEFDB9753171122334455667788"))
{
a.ReadLimbs(dest, 1, 2, 3);
a.ReadLimbs(dest, 2, 2, 6);
Assert.AreEqual(Platform.Ui(0x2468ACEFDB975317UL, 0x11223344U), dest[3]);
Assert.AreEqual(Platform.Ui(0x123456789ABCDEF0UL, 0xDB975317U), dest[4]);
Assert.AreEqual(Platform.Ui(0x123456789ABCDEF0UL, 0xDB975317U), dest[6]);
Assert.AreEqual(Platform.Ui(0x0000000000055533UL, 0x2468ACEFU), dest[7]);
}
}

[TestMethod]
public void IntModifyLimbs()
{
var src = new[]
{
Platform.Ui(0, 0),
Platform.Ui(0, 0),
Platform.Ui(0, 0),
Platform.Ui(0x2468ACEFDB975317UL, 0x11223344U),
Platform.Ui(0x3456789ABCDEF044UL, 0x09872458U),
Platform.Ui(0, 0),
Platform.Ui(0x123456789ABCDEF0UL, 0xDB975317U),
Platform.Ui(0x0000000000055533UL, 0x2468ACEFU),
};

using (var a = new HugeInt(Platform.Select("0x1122334455667788", "0x55667788")))
using (var expected1 = new HugeInt(Platform.Select( "0x3456789ABCDEF0442468ACEFDB9753171122334455667788", "0x098724581122334455667788")))
using (var expected2 = new HugeInt(Platform.Select("-0x55533123456789ABCDEF02468ACEFDB9753171122334455667788", "-0x2468ACEFDB9753171122334455667788")))
{
a.ModifyLimbs(src, 1, 2, 3, false);
Assert.AreEqual(expected1, a);

a.ModifyLimbs(src, 2, 2, 6, true);
Assert.AreEqual(expected2, a);
}
}

[TestMethod]
public void IntModifyLimbsWithGap()
{
var src = new[]
{
Platform.Ui(0, 0),
Platform.Ui(0, 0),
Platform.Ui(0, 0),
Platform.Ui(0x2468ACEFDB975317UL, 0x11223344U),
Platform.Ui(0x3456789ABCDEF044UL, 0x09872458U),
Platform.Ui(0, 0),
Platform.Ui(0x123456789ABCDEF0UL, 0xDB975317U),
Platform.Ui(0x0000000000055533UL, 0x2468ACEFU),
};

using (var a = new HugeInt(Platform.Select("0x1122334455667788", "0x55667788")))
using (var expected = new HugeInt(Platform.Select("0x3456789ABCDEF0442468ACEFDB97531700000000000000001122334455667788", "0x09872458112233440000000055667788")))
{
a.ModifyLimbs(src, 2, 2, 3, false);
Assert.AreEqual(expected, a);
}
}

[TestMethod]
public void IntWriteLimbs()
{
var src = new[]
{
Platform.Ui(0, 0),
Platform.Ui(0, 0),
Platform.Ui(0, 0),
Platform.Ui(0x2468ACEFDB975317UL, 0x11223344U),
Platform.Ui(0x3456789ABCDEF044UL, 0x09872458U),
Platform.Ui(0, 0),
Platform.Ui(0x123456789ABCDEF0UL, 0xDB975317U),
Platform.Ui(0x0000000000055533UL, 0x2468ACEFU),
};

using (var a = new HugeInt(Platform.Select("0x1122334455667788", "0x55667788")))
using (var expected = new HugeInt(Platform.Select("-0x123456789ABCDEF000000000000000003456789ABCDEF0442468ACEFDB975317", "-0xDB975317000000000987245811223344")))
{
a.WriteLimbs(src, 3, 4, false);
Assert.IsTrue(-expected == a);

a.WriteLimbs(src, 3, 4, true);
Assert.AreEqual(expected, a);
}
}
//more tests coming here
}
}
51 changes: 51 additions & 0 deletions mpir.net/mpir.net/HugeInt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,57 @@ namespace MPIR
return nread;
}

void MPTYPE::ReadLimbs(array<mpir_ui>^ destination, int start, int length, int destinationIndex)
{
if (start < 0) throw gcnew ArgumentException("Invalid start", "start");
if (length <= 0) throw gcnew ArgumentException("Invalid length", "length");
if (_value->_mp_alloc < start + length) throw gcnew ArgumentException("Insufficient allocated limb data", "length");
if (destinationIndex < 0) throw gcnew ArgumentException("Invalid destination index", "destinationIndex");
if (destination->Length < destinationIndex + length) throw gcnew ArgumentException("Insufficient destination array size", "destinationIndex");

auto src = &MP(limbs_read)(_value)[start];
for (int i = 0; i < length; i++)
{
destination[destinationIndex++] = *src++;
}
}

void MPTYPE::ModifyLimbs(array<mpir_ui>^ source, int start, int length, int sourceIndex, bool negative)
{
if (start < 0) throw gcnew ArgumentException("Invalid start", "start");
if (length <= 0) throw gcnew ArgumentException("Invalid length", "length");
if (sourceIndex < 0) throw gcnew ArgumentException("Invalid source index", "sourceIndex");
if (source->Length < sourceIndex + length) throw gcnew ArgumentException("Insufficient source array size", "sourceIndex");

auto oldAbsSize = ABS(_value->_mp_size);
auto newSize = MAX(_value->_mp_alloc, start + length);

auto ptr = MP(limbs_modify)(_value, newSize);
auto dest = &ptr[oldAbsSize];
for (int i = oldAbsSize; i < start; i++)
*dest++ = 0;

dest = &ptr[start];
for (int i = 0; i < length; i++)
*dest++ = source[sourceIndex++];

MP(limbs_finish)(_value, negative ? -newSize : newSize);
}

void MPTYPE::WriteLimbs(array<mpir_ui>^ source, int sourceIndex, mp_size_t newSize, bool negative)
{
auto length = newSize;
if (length == 0) throw gcnew ArgumentException("Invalid new size", "newSize");
if (sourceIndex < 0) throw gcnew ArgumentException("Invalid source index", "sourceIndex");
if (source->Length < sourceIndex + length) throw gcnew ArgumentException("Insufficient source array size", "sourceIndex");

auto dest = MP(limbs_write)(_value, length);
for (mp_size_t i = 0; i < length; i++)
*dest++ = source[sourceIndex++];

MP(limbs_finish)(_value, negative ? -newSize : newSize);
}

#pragma endregion

#pragma region number-theoretic
Expand Down
34 changes: 34 additions & 0 deletions mpir.net/mpir.net/HugeInt.h
Original file line number Diff line number Diff line change
Expand Up @@ -2044,6 +2044,40 @@ namespace MPIR
return data;
}

/// <summary>
/// Reads limb data from the number into an array.
/// </summary>
/// <param name="destination">The destination array into which limb data will be copied</param>
/// <param name="start">The 0-based index of the first limb to copy</param>
/// <param name="length">The number of limbs to copy</param>
/// <param name="destinationIndex">The starting index within the <paramref name="destination"/> array that will receive the first copied limb.</param>
void ReadLimbs(array<mpir_ui>^ destination, int start, int length, int destinationIndex);

/// <summary>
/// Modifies a portion or all of the limb data within the number by copying from an array.
/// <para>The number is reallocated if necessary to accommodate the limbs.
/// </para>The previous limb data is preserved, so that partial writes are supported.
/// <para>If a partial write begins beyond the currently allocated limb array, any gap is zeroed out.
/// </para></summary>
/// <param name="source">The source array from which limb data will be copied. The limb data need not be normalized</param>
/// <param name="start">The 0-based index within the destination number's limb data that will receive the first copied limb</param>
/// <param name="length">The number of limbs to copy</param>
/// <param name="sourceIndex">The starting index within the <paramref name="source"/> array from which the first limb is to be copied.</param>
/// <param name="negative">Specifies the new sign of the number: true if negative, false if non-negative</param>
void ModifyLimbs(array<mpir_ui>^ source, int start, int length, int sourceIndex, bool negative);

/// <summary>
/// Writes limb data into the number from an array.
/// <para>The number is reallocated if necessary to accommodate the limbs.
/// </para>The previous limb data is not used; this method is suitable for full replacement of limb data only.
/// </summary>
/// <param name="source">The source array from which limb data will be copied</param>
/// <param name="newSize">The new size of the number. The absolute value is the number of limbs to copy, and will be the new number of limbs, and the sign is the new sign of the number.
/// <para>Copying always starts at the beginning of the number's (re-)allocated limb data. The new limb data must be valid, but need not be normalized</para></param>
/// <param name="sourceIndex">The starting index within the <paramref name="source"/> array from which the first limb is to be copied.</param>
/// <param name="negative">Specifies the new sign of the number: true if negative, false if non-negative</param>
void WriteLimbs(array<mpir_ui>^ source, int sourceIndex, mp_size_t newSize, bool negative);

internal:
size_t ReadNoWhite(TextReader^ reader, int base, size_t nread);

Expand Down

0 comments on commit e10eae8

Please sign in to comment.