The BigInteger class has a method that returns a byte array. Is that indicative of the fact that the class uses a byte array internally as well to store numbers?
This is important to know in order to pick the right data types to manipulate binary data. If the class were, for example, to use an Int64 array, then a similar array would be more efficient to manipulate raw data by any calling functions.
As an example, I am calling the ToByteArray method to traverse bytes looking for specific binary patterns.
According to the reference source it appears that it stores it's information as a uint[]
for the data and a int for the sign.
namespace System.Numerics
{
/// <summary>Represents an arbitrarily large signed integer.</summary>
[Serializable]
public struct BigInteger : IFormattable, IComparable, IComparable<BigInteger>, IEquatable<BigInteger>
{
// For values int.MinValue < n <= int.MaxValue, the value is stored in sign
// and _bits is null. For all other values, sign is +1 or -1 and the bits are in _bits
internal int _sign;
internal uint[] _bits;
Here is the code it executes to perform ToByteArray()
// Return the value of this BigInteger as a little-endian twos-complement
// byte array, using the fewest number of bytes possible. If the value is zero,
// return an array of one byte whose element is 0x00.
public byte[] ToByteArray() {
if (_bits == null && _sign == 0)
return new byte[] { 0 };
// We could probably make this more efficient by eliminating one of the passes.
// The current code does one pass for uint array -> byte array conversion,
// and then another pass to remove unneeded bytes at the top of the array.
uint[] dwords;
byte highByte;
if (_bits == null) {
dwords = new uint[] { (uint)_sign };
highByte = (byte)((_sign < 0) ? 0xff : 0x00);
}
else if(_sign == -1) {
dwords = (uint[])_bits.Clone();
NumericsHelpers.DangerousMakeTwosComplement(dwords); // mutates dwords
highByte = 0xff;
} else {
dwords = _bits;
highByte = 0x00;
}
byte[] bytes = new byte[checked(4 * dwords.Length)];
int curByte = 0;
uint dword;
for (int i = 0; i < dwords.Length; i++) {
dword = dwords[i];
for (int j = 0; j < 4; j++) {
bytes[curByte++] = (byte)(dword & 0xff);
dword >>= 8;
}
}
// find highest significant byte
int msb;
for (msb = bytes.Length - 1; msb > 0; msb--) {
if (bytes[msb] != highByte) break;
}
// ensure high bit is 0 if positive, 1 if negative
bool needExtraByte = (bytes[msb] & 0x80) != (highByte & 0x80);
byte[] trimmedBytes = new byte[msb + 1 + (needExtraByte ? 1 : 0)];
Array.Copy(bytes, trimmedBytes, msb + 1);
if (needExtraByte) trimmedBytes[trimmedBytes.Length - 1] = highByte;
return trimmedBytes;
}