Skip to content

Commit f0b091d

Browse files
committed
OmittedLength
1 parent edc6a57 commit f0b091d

File tree

1 file changed

+81
-108
lines changed

1 file changed

+81
-108
lines changed

src/libraries/System.Runtime.Numerics/src/System/Number.BigInteger.cs

+81-108
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,7 @@ internal const
569569
int
570570
BigIntegerParseNaiveThreshold = 1233,
571571
BigIntegerParseNaiveThresholdInRecursive = 9 * (1 << 7);
572+
572573
private static ParsingStatus NumberToBigInteger(ref NumberBuffer number, out BigInteger result)
573574
{
574575
const uint TenPowMaxPartial = PowersOf1e9.TenPowMaxPartial;
@@ -647,7 +648,6 @@ static bool DivideAndConquer(ref NumberBuffer number, scoped Span<uint> bits)
647648

648649
PowersOf1e9 powersOf1e9 = new PowersOf1e9(powersOf1e9Buffer);
649650

650-
const double digitRatio = 0.103810253; // log_{2^32}(10)
651651

652652
if (trailingZeroCount > 0)
653653
{
@@ -662,29 +662,10 @@ static bool DivideAndConquer(ref NumberBuffer number, scoped Span<uint> bits)
662662
Recursive(powersOf1e9, intDigits, leading);
663663
leading = leading.Slice(0, BigIntegerCalculator.ActualLength(leading));
664664

665-
int trailingZeroBufferLength = checked((int)(digitRatio * trailingZeroCount) + 2);
666-
uint[]? trailingZeroBufferFromPool = null;
667-
Span<uint> trailingZeroBuffer = (
668-
trailingZeroBufferLength <= BigIntegerCalculator.StackAllocThreshold
669-
? stackalloc uint[BigIntegerCalculator.StackAllocThreshold]
670-
: trailingZeroBufferFromPool = ArrayPool<uint>.Shared.Rent(trailingZeroBufferLength)).Slice(0, trailingZeroBufferLength);
671-
trailingZeroBuffer.Clear();
672-
673-
powersOf1e9.CalculatePowerOfTen(trailingZeroCount, trailingZeroBuffer);
674-
trailingZeroBuffer = trailingZeroBuffer.Slice(0, BigIntegerCalculator.ActualLength(trailingZeroBuffer));
675-
676-
// Merge leading and trailing
677-
Span<uint> bitsResult = bits.Slice(0, trailingZeroBuffer.Length + leading.Length);
678-
679-
if (trailingZeroBuffer.Length < leading.Length)
680-
BigIntegerCalculator.Multiply(leading, trailingZeroBuffer, bitsResult);
681-
else
682-
BigIntegerCalculator.Multiply(trailingZeroBuffer, leading, bitsResult);
665+
powersOf1e9.MultiplyPowerOfTen(leading, trailingZeroCount, bits);
683666

684667
if (leadingFromPool != null)
685668
ArrayPool<uint>.Shared.Return(leadingFromPool);
686-
if (trailingZeroBufferFromPool != null)
687-
ArrayPool<uint>.Shared.Return(trailingZeroBufferFromPool);
688669
}
689670
else
690671
{
@@ -730,7 +711,7 @@ static void Recursive(in PowersOf1e9 powersOf1e9, ReadOnlySpan<byte> digits, Spa
730711
Recursive(powersOf1e9, digitsUpper, upperBuffer);
731712
upperBuffer = upperBuffer.Slice(0, BigIntegerCalculator.ActualLength(upperBuffer));
732713
ReadOnlySpan<uint> multiplier = powersOf1e9.GetSpan(log2);
733-
int multiplierTrailingZeroCountUInt32 = (MaxPartialDigits * (1 << log2)) >> 5;
714+
int multiplierTrailingZeroCountUInt32 = PowersOf1e9.OmittedLength(log2);
734715

735716
Span<uint> bitsUpper = bits.Slice(0, upperBuffer.Length + multiplier.Length + multiplierTrailingZeroCountUInt32);
736717
bitsUpper = bitsUpper.Slice(multiplierTrailingZeroCountUInt32);
@@ -968,132 +949,124 @@ public PowersOf1e9(Span<uint> pow1E9)
968949
}
969950
#endif
970951
}
952+
953+
public static int GetBufferSize(int digits)
954+
{
955+
int scale1E9 = digits / MaxPartialDigits;
956+
int log2 = BitOperations.Log2((uint)scale1E9) + 1;
957+
return (uint)log2 < (uint)Indexes.Length ? Indexes[log2] + 1 : Indexes[^1];
958+
}
959+
971960
public ReadOnlySpan<uint> GetSpan(int index)
972961
{
973-
// Returns 1E9^(1<<index) >> (32*(9*(1<<index)/32)
962+
// Returns 1E9^(1<<index) >> (32*(9*(1<<index)/32))
974963
int from = Indexes[index];
975964
int toExclusive = Indexes[index + 1];
976-
return pow1E9[from..toExclusive];
965+
return pow1E9.Slice(from, toExclusive - from);
977966
}
978967

979-
public void CalculatePowerOfTen(int trailingZeroCount, Span<uint> bits)
968+
public static int OmittedLength(int index)
980969
{
981-
Debug.Assert(bits.Length > unchecked((int)(0.934292276687070661 / 9 * trailingZeroCount)) + 1);
982-
Debug.Assert(trailingZeroCount >= 0);
983-
984-
int trailingPartialCount = Math.DivRem(trailingZeroCount, MaxPartialDigits, out int remainingTrailingZeroCount);
970+
// Returns 9*(1<<index)/32
971+
return (MaxPartialDigits * (1 << index)) >> 5;
972+
}
985973

986-
if (trailingPartialCount == 0)
974+
public void MultiplyPowerOfTen(ReadOnlySpan<uint> left, int trailingZeroCount, Span<uint> bits)
975+
{
976+
Debug.Assert(trailingZeroCount >= 0);
977+
if (trailingZeroCount <= UInt32PowersOfTen.Length)
987978
{
988-
bits[0] = UInt32PowersOfTen[remainingTrailingZeroCount];
979+
BigIntegerCalculator.Multiply(left, UInt32PowersOfTen[trailingZeroCount], bits.Slice(0, left.Length + 1));
989980
return;
990981
}
991982

992-
int popCount = BitOperations.PopCount((uint)trailingPartialCount);
983+
uint[]? powersOfTenFromPool = null;
993984

994-
int bits2Length = (bits.Length + 1) >> 1;
995-
uint[]? bits2FromPool = null;
996-
scoped Span<uint> bits2;
997-
if (popCount > 1)
998-
{
999-
bits2 = (
1000-
bits2Length <= BigIntegerCalculator.StackAllocThreshold
1001-
? stackalloc uint[BigIntegerCalculator.StackAllocThreshold]
1002-
: bits2FromPool = ArrayPool<uint>.Shared.Rent(bits2Length)).Slice(0, bits2Length);
1003-
bits2.Clear();
1004-
}
1005-
else
1006-
bits2 = default;
1007-
1008-
int curLength, curTrailingZeroCount;
1009-
scoped Span<uint> curBits, otherBits;
985+
Span<uint> powersOfTen = (
986+
bits.Length <= BigIntegerCalculator.StackAllocThreshold
987+
? stackalloc uint[BigIntegerCalculator.StackAllocThreshold]
988+
: powersOfTenFromPool = ArrayPool<uint>.Shared.Rent(bits.Length)).Slice(0, bits.Length);
989+
scoped Span<uint> powersOfTen2 = bits;
1010990

1011-
if ((popCount & 1) != 0)
1012-
{
1013-
curBits = bits;
1014-
otherBits = bits2;
1015-
}
1016-
else
1017-
{
1018-
curBits = bits2;
1019-
otherBits = bits;
1020-
}
991+
int trailingPartialCount = Math.DivRem(trailingZeroCount, MaxPartialDigits, out int remainingTrailingZeroCount);
1021992

1022-
// Copy first
1023993
int fi = BitOperations.TrailingZeroCount(trailingPartialCount);
1024-
{
1025-
curTrailingZeroCount = MaxPartialDigits * (1 << fi);
1026-
trailingPartialCount >>= fi;
1027-
trailingPartialCount >>= 1;
994+
int omittedLength = OmittedLength(fi);
1028995

1029-
ReadOnlySpan<uint> first = GetSpan(fi);
1030-
first.CopyTo(curBits.Slice(curTrailingZeroCount >> 5));
996+
// Copy first
997+
ReadOnlySpan<uint> first = GetSpan(fi);
998+
int curLength = first.Length;
999+
trailingPartialCount >>= fi;
1000+
trailingPartialCount >>= 1;
10311001

1032-
curLength = first.Length;
1002+
if ((BitOperations.PopCount((uint)trailingPartialCount) & 1) != 0)
1003+
{
1004+
powersOfTen2 = powersOfTen;
1005+
powersOfTen = bits;
1006+
powersOfTen2.Clear();
10331007
}
10341008

1009+
first.CopyTo(powersOfTen);
10351010

1036-
for (int i = fi + 1; trailingPartialCount != 0 && i + 1 < Indexes.Length; i++, trailingPartialCount >>= 1)
1011+
for (++fi; trailingPartialCount != 0; ++fi, trailingPartialCount >>= 1)
10371012
{
1038-
Debug.Assert(GetSpan(i).Length >= curLength - (curTrailingZeroCount >> 5));
1013+
Debug.Assert(fi + 1 < Indexes.Length);
10391014
if ((trailingPartialCount & 1) != 0)
10401015
{
1041-
int powerTrailingZeroCount = MaxPartialDigits * (1 << i);
1042-
int powerTrailingZeroCountUInt32 = powerTrailingZeroCount >> 5;
1043-
int curTrailingZeroCountUInt32 = curTrailingZeroCount >> 5;
1044-
1045-
ReadOnlySpan<uint> power = GetSpan(i);
1046-
Span<uint> src = curBits.Slice(0, curLength);
1047-
Span<uint> dst = otherBits.Slice(0, curLength += power.Length + powerTrailingZeroCountUInt32);
1048-
1049-
Debug.Assert(curTrailingZeroCountUInt32 < src.Length
1050-
&& src.Slice(0, curTrailingZeroCountUInt32).Trim(0u).Length == 0
1051-
&& src[curTrailingZeroCountUInt32] != 0);
1016+
omittedLength += OmittedLength(fi);
10521017

1053-
BigIntegerCalculator.Multiply(power, src.Slice(curTrailingZeroCountUInt32), dst.Slice(powerTrailingZeroCountUInt32 + curTrailingZeroCountUInt32));
1018+
ReadOnlySpan<uint> power = GetSpan(fi);
1019+
Span<uint> src = powersOfTen.Slice(0, curLength);
1020+
Span<uint> dst = powersOfTen2.Slice(0, curLength += power.Length);
10541021

1055-
curTrailingZeroCount += powerTrailingZeroCount;
1022+
if (power.Length < src.Length)
1023+
BigIntegerCalculator.Multiply(src, power, dst);
1024+
else
1025+
BigIntegerCalculator.Multiply(power, src, dst);
10561026

1057-
Span<uint> tmp = curBits;
1058-
curBits = otherBits;
1059-
otherBits = tmp;
1060-
otherBits.Clear();
1027+
Span<uint> tmp = powersOfTen;
1028+
powersOfTen = powersOfTen2;
1029+
powersOfTen2 = tmp;
1030+
powersOfTen2.Clear();
10611031

10621032
// Trim
1063-
while (--curLength >= 0 && curBits[curLength] == 0) ;
1033+
while (--curLength >= 0 && powersOfTen[curLength] == 0) ;
10641034
++curLength;
10651035
}
10661036
}
10671037

1068-
Debug.Assert(Unsafe.AreSame(ref bits[0], ref curBits[0]));
1038+
Debug.Assert(Unsafe.AreSame(ref bits[0], ref powersOfTen2[0]));
10691039

1070-
curBits = curBits.Slice(0, curLength);
1071-
uint multiplier = UInt32PowersOfTen[remainingTrailingZeroCount];
1072-
uint carry = 0;
1073-
for (int i = (curTrailingZeroCount >> 5); i < curBits.Length; i++)
1074-
{
1075-
ulong p = (ulong)multiplier * curBits[i] + carry;
1076-
curBits[i] = (uint)p;
1077-
carry = (uint)(p >> 32);
1078-
}
1040+
powersOfTen = powersOfTen.Slice(0, curLength);
1041+
Span<uint> bits2 = bits.Slice(omittedLength, curLength += left.Length);
1042+
if (left.Length < powersOfTen.Length)
1043+
BigIntegerCalculator.Multiply(powersOfTen, left, bits2);
1044+
else
1045+
BigIntegerCalculator.Multiply(left, powersOfTen, bits2);
10791046

1080-
if (carry != 0)
1081-
{
1082-
bits[curLength] = carry;
1083-
}
1047+
if (powersOfTenFromPool != null)
1048+
ArrayPool<uint>.Shared.Return(powersOfTenFromPool);
10841049

1085-
if (bits2FromPool != null)
1086-
ArrayPool<uint>.Shared.Return(bits2FromPool);
1087-
}
1050+
if (remainingTrailingZeroCount > 0)
1051+
{
1052+
uint multiplier = UInt32PowersOfTen[remainingTrailingZeroCount];
1053+
uint carry = 0;
1054+
for (int i = 0; i < bits2.Length; i++)
1055+
{
1056+
ulong p = (ulong)multiplier * bits2[i] + carry;
1057+
bits2[i] = (uint)p;
1058+
carry = (uint)(p >> 32);
1059+
}
10881060

1089-
public static int GetBufferSize(int digits)
1090-
{
1091-
int scale1E9 = digits / MaxPartialDigits;
1092-
int log2 = BitOperations.Log2((uint)scale1E9) + 1;
1093-
return (uint)log2 < (uint)Indexes.Length ? Indexes[log2] + 1 : Indexes[^1];
1061+
if (carry != 0)
1062+
{
1063+
bits[curLength] = carry;
1064+
}
1065+
}
10941066
}
10951067
}
10961068

1069+
10971070
internal static char ParseFormatSpecifier(ReadOnlySpan<char> format, out int digits)
10981071
{
10991072
digits = -1;

0 commit comments

Comments
 (0)