Skip to content

[resubmit] BigInteger parsing optimization for large decimal string - #55121

Merged
tannergooding merged 16 commits into
dotnet:mainfrom
key-moon:bigint-parse-divide-conquer
Mar 23, 2022
Merged

[resubmit] BigInteger parsing optimization for large decimal string#55121
tannergooding merged 16 commits into
dotnet:mainfrom
key-moon:bigint-parse-divide-conquer

Conversation

@key-moon

Copy link
Copy Markdown
Contributor

I accidentally deleted the forked repository, so I will resubmit the PR #51953 . Please refer to the previous discussion there. I apologize for the inconvenience.

Current BigNumer.NumberToBigInteger method is implemented using naive algorithm. It runs in Θ(N^2) time where N is number of digits. I implemented faster method known as divide-and-conquer algorithm. It runs Θ(N (log(N))^2). Since this algorithms running time has large constant factor, naive method is faster when N is small. So This method is only apply when N is large enough. (specifically, use divide-and-conquer method when N is more than 20000.)

I created branch from #47842 as it looks like #47842 will be merged shortly.

benchmark result

Previous method
BenchmarkDotNet=v0.12.1.1528-nightly, OS=Windows 10.0.19042.928 (20H2/October2020Update)
Intel Core i7-7500U CPU 2.70GHz (Kaby Lake), 1 CPU, 4 logical and 2 physical cores
.NET SDK=6.0.100-preview.3.21202.5
[Host] : .NET 6.0.0 (6.0.21.20104), X64 RyuJIT
Job-CHCQPG : .NET 6.0.0 (42.42.42.42424), X64 RyuJIT
PowerPlanMode=00000000-0000-0000-0000-000000000000 Arguments=/p:DebugType=portable Toolchain=CoreRun IterationTime=250.0000 ms MaxIterationCount=20 MinIterationCount=15 WarmupCount=1 
MethodnumberStringMeanErrorStdDevMedianMinMaxGen 0Gen 1Gen 2Allocated
Parse12345678901(...)01234567890 [20000]2.611 ms0.1786 ms0.2057 ms2.661 ms2.208 ms2.996 ms26.7857--56 KB
Parse12345678901(...)01234567890 [40000]9.028 ms0.7436 ms0.8265 ms8.816 ms8.072 ms10.909 ms31.2500--96 KB
Parse12345678901(...)01234567890 [60000]18.521 ms0.5179 ms0.5756 ms18.552 ms17.349 ms19.541 ms71.4286--151 KB
Parse12345678901(...)01234567890 [80000]32.904 ms1.1486 ms1.2290 ms32.761 ms30.984 ms34.686 ms---191 KB
Parse12345678901(...)01234567890 [100000]51.271 ms1.7700 ms2.0384 ms51.186 ms48.447 ms54.856 ms---246 KB
Parse12345678901(...)01234567890 [120000]74.285 ms3.6392 ms3.8939 ms73.489 ms68.604 ms82.719 ms---286 KB
Parse12345678901(...)01234567890 [140000]100.248 ms5.2825 ms5.8715 ms98.712 ms92.597 ms113.046 ms---341 KB
Parse12345678901(...)01234567890 [160000]127.443 ms4.8226 ms5.5537 ms125.749 ms120.504 ms138.583 ms---381 KB
Parse12345678901(...)01234567890 [180000]162.028 ms4.9852 ms5.7409 ms162.142 ms151.841 ms171.640 ms---436 KB
Parse12345678901(...)01234567890 [200000]224.511 ms16.7864 ms19.3313 ms224.392 ms192.558 ms255.098 ms---476 KB
Parse12345678901(...)01234567890 [220000]240.451 ms10.9087 ms12.1250 ms234.971 ms226.956 ms265.072 ms---531 KB
Parse12345678901(...)01234567890 [240000]300.378 ms25.1560 ms27.9608 ms296.348 ms267.565 ms357.131 ms---572 KB
Parse12345678901(...)01234567890 [260000]346.397 ms26.8156 ms29.8054 ms335.024 ms320.430 ms412.120 ms---626 KB
Parse12345678901(...)01234567890 [280000]384.442 ms12.8365 ms14.2678 ms381.489 ms367.624 ms420.767 ms---666 KB
Parse12345678901(...)01234567890 [300000]433.914 ms9.1847 ms10.5772 ms433.046 ms414.254 ms452.394 ms---721 KB
Implemented method
BenchmarkDotNet=v0.12.1.1528-nightly, OS=Windows 10.0.19042.928 (20H2/October2020Update)
Intel Core i7-7500U CPU 2.70GHz (Kaby Lake), 1 CPU, 4 logical and 2 physical cores
.NET SDK=6.0.100-preview.3.21202.5
[Host] : .NET 6.0.0 (6.0.21.20104), X64 RyuJIT
Job-YASIZJ : .NET 6.0.0 (42.42.42.42424), X64 RyuJIT
PowerPlanMode=00000000-0000-0000-0000-000000000000 Arguments=/p:DebugType=portable Toolchain=CoreRun IterationTime=250.0000 ms MaxIterationCount=20 MinIterationCount=15 WarmupCount=1 
MethodnumberStringMeanErrorStdDevMedianMinMaxGen 0Gen 1Gen 2Allocated
Parse12345678901(...)01234567890 [20000]2.017 ms0.0559 ms0.0643 ms2.024 ms1.921 ms2.127 ms140.6250--288 KB
Parse12345678901(...)01234567890 [40000]6.237 ms0.1116 ms0.0932 ms6.218 ms6.127 ms6.434 ms437.500083.3333-994 KB
Parse12345678901(...)01234567890 [60000]15.522 ms1.3853 ms1.5953 ms15.153 ms13.686 ms18.949 ms1062.5000218.7500-2,831 KB
Parse12345678901(...)01234567890 [80000]20.554 ms0.4685 ms0.5208 ms20.429 ms19.880 ms21.552 ms1181.8182181.8182-3,572 KB
Parse12345678901(...)01234567890 [100000]39.146 ms1.8050 ms1.8536 ms38.681 ms36.992 ms44.189 ms3000.0000333.3333-7,680 KB
Parse12345678901(...)01234567890 [120000]47.999 ms1.5866 ms1.8271 ms47.429 ms46.147 ms51.705 ms3750.0000250.0000-10,447 KB
Parse12345678901(...)01234567890 [140000]41.915 ms1.3341 ms1.3700 ms41.657 ms40.299 ms44.621 ms2166.6667500.0000-6,532 KB
Parse12345678901(...)01234567890 [160000]67.668 ms1.4404 ms1.6010 ms67.296 ms65.587 ms70.763 ms4750.0000250.0000-12,897 KB
Parse12345678901(...)01234567890 [180000]103.943 ms2.4616 ms2.8347 ms103.285 ms100.249 ms109.843 ms6500.0000500.0000-18,962 KB
Parse12345678901(...)01234567890 [200000]136.343 ms3.9093 ms4.0146 ms135.607 ms131.575 ms148.198 ms9500.0000500.0000-28,922 KB
Parse12345678901(...)01234567890 [220000]154.695 ms3.6123 ms3.7096 ms154.182 ms149.801 ms163.375 ms17500.0000500.0000-40,999 KB
Parse12345678901(...)01234567890 [240000]184.792 ms20.8938 ms24.0613 ms173.449 ms163.513 ms234.269 ms16000.00001000.0000-39,244 KB
Parse12345678901(...)01234567890 [260000]160.434 ms3.0439 ms3.5053 ms160.026 ms155.602 ms167.424 ms12500.0000500.0000-33,322 KB
Parse12345678901(...)01234567890 [280000]134.838 ms2.4207 ms2.2644 ms134.531 ms132.314 ms139.587 ms9500.0000500.0000-22,696 KB
Parse12345678901(...)01234567890 [300000]140.690 ms2.4686 ms2.4245 ms141.285 ms134.758 ms144.021 ms7500.00001500.00001000.000024,318 KB

@ghost

ghost commented Jul 3, 2021

Copy link
Copy Markdown

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

Issue Details

I accidentally deleted the forked repository, so I will resubmit the PR #51953 . Please refer to the previous discussion there. I apologize for the inconvenience.

Current BigNumer.NumberToBigInteger method is implemented using naive algorithm. It runs in Θ(N^2) time where N is number of digits. I implemented faster method known as divide-and-conquer algorithm. It runs Θ(N (log(N))^2). Since this algorithms running time has large constant factor, naive method is faster when N is small. So This method is only apply when N is large enough. (specifically, use divide-and-conquer method when N is more than 20000.)

I created branch from #47842 as it looks like #47842 will be merged shortly.

benchmark result

Previous method
BenchmarkDotNet=v0.12.1.1528-nightly, OS=Windows 10.0.19042.928 (20H2/October2020Update)
Intel Core i7-7500U CPU 2.70GHz (Kaby Lake), 1 CPU, 4 logical and 2 physical cores
.NET SDK=6.0.100-preview.3.21202.5
[Host] : .NET 6.0.0 (6.0.21.20104), X64 RyuJIT
Job-CHCQPG : .NET 6.0.0 (42.42.42.42424), X64 RyuJIT
PowerPlanMode=00000000-0000-0000-0000-000000000000 Arguments=/p:DebugType=portable Toolchain=CoreRun IterationTime=250.0000 ms MaxIterationCount=20 MinIterationCount=15 WarmupCount=1 
MethodnumberStringMeanErrorStdDevMedianMinMaxGen 0Gen 1Gen 2Allocated
Parse12345678901(...)01234567890 [20000]2.611 ms0.1786 ms0.2057 ms2.661 ms2.208 ms2.996 ms26.7857--56 KB
Parse12345678901(...)01234567890 [40000]9.028 ms0.7436 ms0.8265 ms8.816 ms8.072 ms10.909 ms31.2500--96 KB
Parse12345678901(...)01234567890 [60000]18.521 ms0.5179 ms0.5756 ms18.552 ms17.349 ms19.541 ms71.4286--151 KB
Parse12345678901(...)01234567890 [80000]32.904 ms1.1486 ms1.2290 ms32.761 ms30.984 ms34.686 ms---191 KB
Parse12345678901(...)01234567890 [100000]51.271 ms1.7700 ms2.0384 ms51.186 ms48.447 ms54.856 ms---246 KB
Parse12345678901(...)01234567890 [120000]74.285 ms3.6392 ms3.8939 ms73.489 ms68.604 ms82.719 ms---286 KB
Parse12345678901(...)01234567890 [140000]100.248 ms5.2825 ms5.8715 ms98.712 ms92.597 ms113.046 ms---341 KB
Parse12345678901(...)01234567890 [160000]127.443 ms4.8226 ms5.5537 ms125.749 ms120.504 ms138.583 ms---381 KB
Parse12345678901(...)01234567890 [180000]162.028 ms4.9852 ms5.7409 ms162.142 ms151.841 ms171.640 ms---436 KB
Parse12345678901(...)01234567890 [200000]224.511 ms16.7864 ms19.3313 ms224.392 ms192.558 ms255.098 ms---476 KB
Parse12345678901(...)01234567890 [220000]240.451 ms10.9087 ms12.1250 ms234.971 ms226.956 ms265.072 ms---531 KB
Parse12345678901(...)01234567890 [240000]300.378 ms25.1560 ms27.9608 ms296.348 ms267.565 ms357.131 ms---572 KB
Parse12345678901(...)01234567890 [260000]346.397 ms26.8156 ms29.8054 ms335.024 ms320.430 ms412.120 ms---626 KB
Parse12345678901(...)01234567890 [280000]384.442 ms12.8365 ms14.2678 ms381.489 ms367.624 ms420.767 ms---666 KB
Parse12345678901(...)01234567890 [300000]433.914 ms9.1847 ms10.5772 ms433.046 ms414.254 ms452.394 ms---721 KB
Implemented method
BenchmarkDotNet=v0.12.1.1528-nightly, OS=Windows 10.0.19042.928 (20H2/October2020Update)
Intel Core i7-7500U CPU 2.70GHz (Kaby Lake), 1 CPU, 4 logical and 2 physical cores
.NET SDK=6.0.100-preview.3.21202.5
[Host] : .NET 6.0.0 (6.0.21.20104), X64 RyuJIT
Job-YASIZJ : .NET 6.0.0 (42.42.42.42424), X64 RyuJIT
PowerPlanMode=00000000-0000-0000-0000-000000000000 Arguments=/p:DebugType=portable Toolchain=CoreRun IterationTime=250.0000 ms MaxIterationCount=20 MinIterationCount=15 WarmupCount=1 
MethodnumberStringMeanErrorStdDevMedianMinMaxGen 0Gen 1Gen 2Allocated
Parse12345678901(...)01234567890 [20000]2.017 ms0.0559 ms0.0643 ms2.024 ms1.921 ms2.127 ms140.6250--288 KB
Parse12345678901(...)01234567890 [40000]6.237 ms0.1116 ms0.0932 ms6.218 ms6.127 ms6.434 ms437.500083.3333-994 KB
Parse12345678901(...)01234567890 [60000]15.522 ms1.3853 ms1.5953 ms15.153 ms13.686 ms18.949 ms1062.5000218.7500-2,831 KB
Parse12345678901(...)01234567890 [80000]20.554 ms0.4685 ms0.5208 ms20.429 ms19.880 ms21.552 ms1181.8182181.8182-3,572 KB
Parse12345678901(...)01234567890 [100000]39.146 ms1.8050 ms1.8536 ms38.681 ms36.992 ms44.189 ms3000.0000333.3333-7,680 KB
Parse12345678901(...)01234567890 [120000]47.999 ms1.5866 ms1.8271 ms47.429 ms46.147 ms51.705 ms3750.0000250.0000-10,447 KB
Parse12345678901(...)01234567890 [140000]41.915 ms1.3341 ms1.3700 ms41.657 ms40.299 ms44.621 ms2166.6667500.0000-6,532 KB
Parse12345678901(...)01234567890 [160000]67.668 ms1.4404 ms1.6010 ms67.296 ms65.587 ms70.763 ms4750.0000250.0000-12,897 KB
Parse12345678901(...)01234567890 [180000]103.943 ms2.4616 ms2.8347 ms103.285 ms100.249 ms109.843 ms6500.0000500.0000-18,962 KB
Parse12345678901(...)01234567890 [200000]136.343 ms3.9093 ms4.0146 ms135.607 ms131.575 ms148.198 ms9500.0000500.0000-28,922 KB
Parse12345678901(...)01234567890 [220000]154.695 ms3.6123 ms3.7096 ms154.182 ms149.801 ms163.375 ms17500.0000500.0000-40,999 KB
Parse12345678901(...)01234567890 [240000]184.792 ms20.8938 ms24.0613 ms173.449 ms163.513 ms234.269 ms16000.00001000.0000-39,244 KB
Parse12345678901(...)01234567890 [260000]160.434 ms3.0439 ms3.5053 ms160.026 ms155.602 ms167.424 ms12500.0000500.0000-33,322 KB
Parse12345678901(...)01234567890 [280000]134.838 ms2.4207 ms2.2644 ms134.531 ms132.314 ms139.587 ms9500.0000500.0000-22,696 KB
Parse12345678901(...)01234567890 [300000]140.690 ms2.4686 ms2.4245 ms141.285 ms134.758 ms144.021 ms7500.00001500.00001000.000024,318 KB
Author:key-moon
Assignees:-
Labels:

area-System.Numerics

Milestone:-

@terrajobstterrajobst added the community-contribution Indicates that the PR has been added by a community member label Jul 19, 2021
@jeffhandley

Copy link
Copy Markdown
Member

@tannergooding This PR is assigned to you for follow-up/decision before the RC1 snap.

@tannergooding

Copy link
Copy Markdown
Member

Thanks for the contribution here @key-moon. Due to it being so late in the cycle, this is going to miss out on the .NET 6 release and we'll instead be able to merge it after the RC1 snap and we begin accepting changes for .NET 7 (ETA: 3-4 weeks)

@tannergoodingtannergooding added this to the 7.0.0 milestone Aug 2, 2021
@jeffhandley

Copy link
Copy Markdown
Member

@key-moon I wanted to let you know we're still working on some .NET 6.0 RC2 items, so we're a bit delayed on reviewing this. It'll likely be a couple more weeks. Thanks for your contributions and patience!

{
foreach (ReadOnlyMemory<char> digitsChunk in number.digits.GetChunks())
if (number.digits.Length <= s_naiveThreshold)
{

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given how big each path is, I would if it would be better to break them into 2 helper methods. Basically leaving:

if(number.digits.Length<=s_naiveThreshold){AlgorithmA(...);}else{AlgorithmB(...);}

-- The method is getting pretty big, which means the JIT might give up on optimizing it otherwise (haven't confirmed if it actually does).

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for late replying. I think this is worth doing in terms of improving readability. I will implement it as soon as possible.

@key-moonkey-moonOct 9, 2021

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have implemented and benchmarked. As a result, there is no significant difference in speed and memory. However, readability has definitely been improved.

Benchmark result
  • Job-VEBSQX: before split to methods (a9942c5)
  • Job-HLAVXS: after split to methods (460664f)
BenchmarkDotNet=v0.13.1.1611-nightly, OS=Windows 10.0.22000
11th Gen Intel Core i7-1165G7 2.80GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK=6.0.100-rc.1.21463.6
[Host] : .NET 5.0.9 (5.0.921.35908), X64 RyuJIT
Job-VEBSQX : .NET 6.0.0 (42.42.42.42424), X64 RyuJIT
Job-HLAVXS : .NET 6.0.0 (42.42.42.42424), X64 RyuJIT
PowerPlanMode=00000000-0000-0000-0000-000000000000 Arguments=/p:DebugType=portable,-bl:benchmarkdotnet.binlog IterationTime=250.0000 ms MaxIterationCount=20 MinIterationCount=15 WarmupCount=1 
MethodJobToolchainnumberStringMeanErrorStdDevMedianMinMaxRatioRatioSDGen 0Gen 1Gen 2Allocated
ParseJob-VEBSQX\artifacts-a9942c\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe12345678901(...)01234567890 [50000]10.50 ms0.350 ms0.389 ms10.56 ms9.902 ms11.42 ms1.000.00312.500093.7500-2 MB
ParseJob-HLAVXS\artifacts-460664\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe12345678901(...)01234567890 [50000]10.29 ms0.384 ms0.427 ms10.34 ms9.563 ms11.13 ms0.980.03312.500093.7500-2 MB
ParseJob-VEBSQX\artifacts-a9942c\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe12345678901(...)01234567890 [100000]36.77 ms1.531 ms1.702 ms36.58 ms33.684 ms40.74 ms1.000.001125.0000250.0000-7 MB
ParseJob-HLAVXS\artifacts-460664\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe12345678901(...)01234567890 [100000]36.64 ms1.445 ms1.606 ms36.23 ms33.401 ms39.95 ms1.000.071166.6667166.6667-7 MB
ParseJob-VEBSQX\artifacts-a9942c\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe12345678901(...)01234567890 [150000]41.08 ms1.350 ms1.555 ms40.75 ms38.486 ms44.25 ms1.000.001000.0000500.0000-7 MB
ParseJob-HLAVXS\artifacts-460664\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe12345678901(...)01234567890 [150000]40.97 ms0.742 ms0.762 ms41.26 ms39.155 ms42.20 ms1.010.041000.0000500.0000-7 MB
ParseJob-VEBSQX\artifacts-a9942c\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe12345678901(...)01234567890 [200000]129.14 ms3.434 ms3.527 ms129.89 ms120.135 ms133.89 ms1.000.004500.0000500.0000-28 MB
ParseJob-HLAVXS\artifacts-460664\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe12345678901(...)01234567890 [200000]130.05 ms2.571 ms2.279 ms130.45 ms125.832 ms134.43 ms1.010.044500.0000500.0000-28 MB
ParseJob-VEBSQX\artifacts-a9942c\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe12345678901(...)01234567890 [250000]160.84 ms8.920 ms9.544 ms158.21 ms146.879 ms179.63 ms1.000.005500.0000500.0000-34 MB
ParseJob-HLAVXS\artifacts-460664\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe12345678901(...)01234567890 [250000]162.85 ms7.046 ms8.114 ms161.09 ms145.608 ms178.37 ms1.010.085500.0000500.0000-34 MB
ParseJob-VEBSQX\artifacts-a9942c\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe12345678901(...)01234567890 [300000]132.28 ms3.731 ms3.992 ms131.79 ms122.929 ms137.93 ms1.000.003500.00001500.00001000.000024 MB
ParseJob-HLAVXS\artifacts-460664\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe12345678901(...)01234567890 [300000]134.72 ms5.300 ms6.103 ms133.63 ms123.651 ms147.27 ms1.030.063500.00001500.00001000.000024 MB
ParseJob-VEBSQX\artifacts-a9942c\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe12345678901(...)01234567890 [350000]356.66 ms20.078 ms21.484 ms351.60 ms321.365 ms406.99 ms1.000.0014000.000012000.000011000.000071 MB
ParseJob-HLAVXS\artifacts-460664\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe12345678901(...)01234567890 [350000]354.54 ms17.497 ms19.448 ms348.05 ms323.012 ms396.16 ms0.990.0715000.000013000.000012000.000071 MB
ParseJob-VEBSQX\artifacts-a9942c\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe12345678901(...)01234567890 [400000]524.19 ms47.271 ms54.437 ms510.63 ms461.465 ms640.54 ms1.000.0017000.00003000.00002000.0000107 MB
ParseJob-HLAVXS\artifacts-460664\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe12345678901(...)01234567890 [400000]553.00 ms91.333 ms105.179 ms487.60 ms444.111 ms710.82 ms1.060.2117000.00003000.00002000.0000107 MB
ParseJob-VEBSQX\artifacts-a9942c\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe12345678901(...)01234567890 [450000]627.40 ms91.780 ms105.695 ms570.04 ms526.129 ms800.22 ms1.000.0024000.00001000.0000-149 MB
ParseJob-HLAVXS\artifacts-460664\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe12345678901(...)01234567890 [450000]554.17 ms49.428 ms56.921 ms542.68 ms472.918 ms657.23 ms0.900.1424000.00001000.0000-149 MB

Comment threadsrc/libraries/System.Runtime.Numerics/src/System/Numerics/BigNumber.cs Outdated
Comment threadsrc/libraries/System.Runtime.Numerics/src/System/Numerics/BigNumber.cs Outdated
Comment threadsrc/libraries/System.Runtime.Numerics/src/System/Numerics/BigNumber.cs Outdated
Comment threadsrc/libraries/System.Runtime.Numerics/src/System/Numerics/BigNumber.cs Outdated
Comment threadsrc/libraries/System.Runtime.Numerics/src/System/Numerics/BigNumber.cs Outdated
Comment threadsrc/libraries/System.Runtime.Numerics/src/System/Numerics/BigNumber.cs Outdated
@tannergooding

Copy link
Copy Markdown
Member

The overall logic LGTM.

I left a couple nits/comments about adding comments and possibly minor refactorings to help with readability when this inevitably is looked at again in the future. I likewise called out a peculiar scenario around handling fractional digits which I don't believe is possible (happy to be proven wrong here).

It would be great if this could get a second pair of eyes on it (CC. @pgovind, @stephentoub, @bartonjs since you've reviewed or worked on BigInteger semi-recently).

Comment threadsrc/libraries/System.Runtime.Numerics/src/System/Numerics/BigNumber.cs Outdated
multiplier[0] = TenPowMaxPartial;

// This loop is executed ceil(log_2(bufferSize)) times.
while (true)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this loop is executed ceil(log_2(bufferSize)), why do you not use a for loop? I think these are better optimized by the JIT.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please benchmark before/after to make sure that this is really the case.

Comment threadsrc/libraries/System.Runtime.Numerics/src/System/Numerics/BigNumber.cs Outdated
}
}

private static volatile TypeInfo s_lazyInternalNumber;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a comment, which explains why this is volatile.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This commits explains the reason. Actually, I didn't understand why volatile is required.
dotnet/corefx@8918578

@tannergooding

Copy link
Copy Markdown
Member

@key-moon are you still working on this?

No particular rush, just wanted to ensure that was the case since many people took a break over the holidays. There are still several pending comments above that would need to be resolved.

@tannergoodingtannergooding added the needs-author-action An issue or pull request that requires more info or actions from the author. label Jan 7, 2022
@key-moon

Copy link
Copy Markdown
ContributorAuthor

Yes, I’m still working on this PR. Sorry for the late response. I'll resolve these conversations as soon as possible.

@ghostghost removed the needs-author-action An issue or pull request that requires more info or actions from the author. label Jan 8, 2022
@tannergoodingtannergooding added the needs-author-action An issue or pull request that requires more info or actions from the author. label Jan 24, 2022
@ghostghost removed the needs-author-action An issue or pull request that requires more info or actions from the author. label Jan 26, 2022
@tannergooding

Copy link
Copy Markdown
Member

This has a merge conflict that needs to be resolved. I also resolved a few comments around styling concerns where the code in question isn't new, rather just being moved around.

While I do think that resolving those styling inconsistencies would be nice, since its not new code I think it can happen in an independent PR.

@tannergooding

Copy link
Copy Markdown
Member

Closing and reopening to try and get helix to pick up the changes and allow CI to actually run.

@tannergooding

Copy link
Copy Markdown
Member

This PR looks generally good, I'd just like to get CI passing before merging.

Merging with main again may allow it to pass.

@deeprobin

Copy link
Copy Markdown
Contributor

Build failures are unrelated

@tannergooding
tannergooding merged commit 8ed8517 into dotnet:mainMar 23, 2022
@danmoseley

Copy link
Copy Markdown
Contributor

Thanks @key-moon for your work on this perf improvement!

radekdoulik pushed a commit to radekdoulik/runtime that referenced this pull request Mar 30, 2022
…otnet#55121)
* implement divide-and-conquer method for parsing digits
* fix argument order in Assert when x equals to 0
* Apply format fix
Co-authored-by: Stephen Toub <stoub@microsoft.com>
* add test for non-naive algorithm
* add description for naiveThreshold
* fix trivial part
* add check for boundary condition
* add assertions and descriptions
* change variable name
* remove inappropreate use of var
* to use ArrayPool<int>.Shared.Rent for newBuffer allocation
* move both algorithms to separate methods
* add and fix comments
* trivial fix
Co-authored-by: Stephen Toub <stoub@microsoft.com>
@ghostghost locked as resolved and limited conversation to collaborators Apr 23, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Numericscommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants

@key-moon@jeffhandley@tannergooding@deeprobin@danmoseley@stephentoub@bartonjs@terrajobst