-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optimize BigInteger.ToString for large decimal string #104676
Conversation
Tagging subscribers to this area: @dotnet/area-system-numerics |
// The Ratio is calculated as: log_{10^9}(2^32) | ||
const double digitRatio = 1.0703288734719332; | ||
Debug.Assert(BigInteger.MaxLength * digitRatio + 1 < Array.MaxLength); // won't overflow |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the length doesn't need to be exact, you can use integer estimation instead, similar to what I did in NumberToBigInteger
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which part are you referring to? NumberToBigInteger
also used
runtime/src/libraries/System.Runtime.Numerics/src/System/Number.BigInteger.cs
Lines 562 to 573 in 264e39c
// shrink buffer to the currently used portion. | |
// First, calculate the rough size of the buffer from the ratio that the number | |
// of digits follows. Then, shrink the size until there is no more space left. | |
// The Ratio is calculated as: log_{2^32}(10^9) | |
const double digitRatio = 0.934292276687070661; | |
currentBufferSize = Math.Min((int)(bufferSize * digitRatio) + 1, bufferSize); | |
Debug.Assert(buffer.Length == currentBufferSize || buffer[currentBufferSize] == 0); | |
while (0 < currentBufferSize && buffer[currentBufferSize - 1] == 0) | |
{ | |
currentBufferSize--; | |
} | |
currentBuffer = buffer.Slice(0, currentBufferSize); |
I rewrote it to use
runtime/src/libraries/System.Runtime.Numerics/src/System/Number.BigInteger.cs
Lines 372 to 379 in 0d426df
const double digitRatio = 0.10381025297; // log_{2^32}(10) | |
int resultLength = checked((int)(digitRatio * number.Scale) + 1 + 2); | |
uint[]? resultBufferFromPool = null; | |
Span<uint> resultBuffer = ( | |
resultLength <= BigIntegerCalculator.StackAllocThreshold | |
? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] | |
: resultBufferFromPool = ArrayPool<uint>.Shared.Rent(resultLength)).Slice(0, resultLength); | |
resultBuffer.Clear(); |
@@ -1109,6 +1210,26 @@ public static int OmittedLength(int index) | |||
return (MaxPartialDigits * (1 << index)) >> 5; | |||
} | |||
|
|||
public static void FloorBufferSize(int size, out int bufferSize, out int maxIndex) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it required to calculate exact buffer length? Can it be relaxed, and let the algorithm to strip unnecessary zeros?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a concise way to calculate the inexact buffer length? It would be most concise to find out from the predefined buffer length.
Draft Pull Request was automatically closed for 30 days of inactivity. Please let us know if you'd like to reopen it. |
This PR is a counterpart to #55121. divide-and-conquer algorithm
Number.FormatBigInteger() can run in$D(n)log(N)$ time using the Divide and Conquer algorithm, where $D(n)$ represents the computational complexity of BigInteger division.
The computational complexity of division will be improved by #96895. Once 96895 is merged, I will add a benchmark and set the PR to "ready for review."