Skip to content

Commit 9f5f44a

Browse files
committed
pre-calculate 1000000000^(1<<5)
1 parent f0b091d commit 9f5f44a

File tree

1 file changed

+73
-20
lines changed

1 file changed

+73
-20
lines changed

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

+73-20
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,7 @@ static BigInteger NumberBufferToBigInteger(ReadOnlySpan<uint> result, bool isNeg
862862
}
863863
internal readonly ref struct PowersOf1e9
864864
{
865+
// Holds 1000000000^(1<<<n).
865866
private readonly ReadOnlySpan<uint> pow1E9;
866867
public const uint TenPowMaxPartial = 1000000000;
867868
public const int MaxPartialDigits = 9;
@@ -879,7 +880,8 @@ internal readonly ref struct PowersOf1e9
879880
// length -= (9*(1<<i)) >> 5;
880881
// indexes[i+1] = indexes[i] + length;
881882
// }
882-
private static ReadOnlySpan<int> Indexes => new int[] {
883+
private static ReadOnlySpan<int> Indexes => new int[]
884+
{
883885
0,
884886
1,
885887
3,
@@ -914,40 +916,91 @@ internal readonly ref struct PowersOf1e9
914916
1939268536,
915917
};
916918

919+
// The PowersOf1e9 structure holds 1000000000^(1<<<n). However, if the lower element is zero,
920+
// it is truncated. Therefore, if the lower element becomes zero in the process of calculating
921+
// 1000000000^(1<<<n), it must be truncated. If 1000000000^(1<<<<n) is calculated in advance
922+
// for less than 6, there is no need to consider the case where the lower element becomes zero
923+
// during the calculation process, since 1000000000^(1<<<<n) mod 32 is always zero.
924+
private static ReadOnlySpan<uint> FivePowers1E9 => new uint[]
925+
{
926+
// 1000000000^(1<<0)
927+
1000000000,
928+
// 1000000000^(1<<1)
929+
2808348672,
930+
232830643,
931+
// 1000000000^(1<<2)
932+
3008077584,
933+
2076772117,
934+
12621774,
935+
// 1000000000^(1<<3)
936+
4130660608,
937+
835571558,
938+
1441351422,
939+
977976457,
940+
264170013,
941+
37092,
942+
// 1000000000^(1<<4)
943+
767623168,
944+
4241160024,
945+
1260959332,
946+
2541775228,
947+
2965753944,
948+
1796720685,
949+
484800439,
950+
1311835347,
951+
2945126454,
952+
3563705203,
953+
1375821026,
954+
// 1000000000^(1<<5)
955+
3940379521,
956+
184513341,
957+
2872588323,
958+
2214530454,
959+
38258512,
960+
2980860351,
961+
114267010,
962+
2188874685,
963+
234079247,
964+
2101059099,
965+
1948702207,
966+
947446250,
967+
864457656,
968+
507589568,
969+
1321007357,
970+
3911984176,
971+
1011110295,
972+
2382358050,
973+
2389730781,
974+
730678769,
975+
440721283,
976+
};
977+
917978
public PowersOf1e9(Span<uint> pow1E9)
918979
{
980+
Debug.Assert(pow1E9.Length >= 1);
981+
Debug.Assert(Indexes[6] == FivePowers1E9.Length);
982+
if (pow1E9.Length < Indexes[7])
983+
{
984+
this.pow1E9 = FivePowers1E9;
985+
return;
986+
}
987+
FivePowers1E9.CopyTo(pow1E9.Slice(0, FivePowers1E9.Length));
919988
this.pow1E9 = pow1E9;
920989

921-
Debug.Assert(pow1E9.Length >= 1);
922-
pow1E9[0] = TenPowMaxPartial;
923-
ReadOnlySpan<uint> src = pow1E9.Slice(0, 1);
924-
int toExclusive = 1;
925-
for (int i = 1; i + 1 < Indexes.Length; i++)
990+
ReadOnlySpan<uint> src = pow1E9.Slice(Indexes[5], Indexes[6] - Indexes[5]);
991+
int toExclusive = Indexes[6];
992+
for (int i = 6; i + 1 < Indexes.Length; i++)
926993
{
927994
Debug.Assert(2 * src.Length - (Indexes[i + 1] - Indexes[i]) is 0 or 1);
928995
if (pow1E9.Length - toExclusive < (src.Length << 1))
929996
break;
930997
Span<uint> dst = pow1E9.Slice(toExclusive, src.Length << 1);
931998
BigIntegerCalculator.Square(src, dst);
932-
if (dst[0] == 0)
933-
{
934-
dst.Slice(1).CopyTo(dst);
935-
dst[^1] = 0;
936-
}
937999
int from = toExclusive;
9381000
toExclusive = Indexes[i + 1];
9391001
src = pow1E9.Slice(from, toExclusive - from);
9401002
Debug.Assert(toExclusive == pow1E9.Length || pow1E9[toExclusive] == 0);
9411003
}
942-
#if DEBUG
943-
for (int i = 0; i + 1 < Indexes.Length; i++)
944-
{
945-
int startIndex = Indexes[i];
946-
int endIndex = Indexes[i + 1];
947-
if (endIndex >= pow1E9.Length) break;
948-
Debug.Assert(pow1E9[startIndex] != 0);
949-
}
950-
#endif
9511004
}
9521005

9531006
public static int GetBufferSize(int digits)

0 commit comments

Comments
 (0)