Skip to content
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

Closed
wants to merge 3 commits into from

Conversation

kzrnm
Copy link
Contributor

@kzrnm kzrnm commented Jul 10, 2024

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."

@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Jul 10, 2024
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-numerics
See info in area-owners.md if you want to be subscribed.

Comment on lines +783 to +785
// 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
Copy link
Member

@huoyaoyuan huoyaoyuan Jul 10, 2024

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.

Copy link
Contributor Author

@kzrnm kzrnm Jul 11, 2024

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 $\log_{2^{32}}(10^9)$.

// 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 $\log_{2^{32}}(10)$ in pull request #97589, but it is essentially the same.

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)
Copy link
Member

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?

Copy link
Contributor Author

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.

Copy link
Contributor

Draft Pull Request was automatically closed for 30 days of inactivity. Please let us know if you'd like to reopen it.

@github-actions github-actions bot locked and limited conversation to collaborators Sep 10, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Numerics community-contribution Indicates that the PR has been added by a community member
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants