Skip to content

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

@ghost ghost added the area-System.Numerics label Jul 10, 2024
@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
@dotnet-policy-service
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();

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.

@dotnet-policy-service
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