Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Optimize BigInteger.Parse#97589

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
tannergooding merged 25 commits intodotnet:mainfromkzrnm:BigIntegerParsePowOf10
Jul 3, 2024

Conversation

kzrnm
Copy link
Contributor

@kzrnmkzrnm commentedJan 27, 2024
edited
Loading

Optimize Multiplier

BigInteger.Parse treats$10^{9\times2^n}$ as a multiplier.
The leading$9\times2^n/32$ items of the array representation of$10^{9\times2^n}$ is zero, so the number of arrays for multiplication can be reduced.

For example, the array represention of$10^{9\times2^8} = 10^{2304}$ has 957 items, of which the leading 288 items are 0.

Parse powers of ten

BigInteger.Parse("1" + new string('0', n)) is too slow. It runs in$O(n^2)$.
This is because trailing zeros are always calculated naively.
I fixed the behavior.

Benchmark

usingBenchmarkDotNet.Attributes;usingBenchmarkDotNet.Running;usingBenchmarkDotNet.Configs;usingSystem.Numerics;usingSystem.Runtime.InteropServices;BenchmarkSwitcher.FromAssembly(typeof(ParseTest).Assembly).Run(args);[DisassemblyDiagnoser][GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByMethod)]publicclassParseTest{[Params(1000,10000,100000,1000000)]publicintN;strings1,s2,s3;[GlobalSetup]publicvoidSetup(){s1="1"+newstring('0',N);s2="1"+newstring('0',N-1)+"1";s3=newstring('9',N);}[Benchmark]publicBigIntegerPowerOfTen()=>BigInteger.Parse(s1);[Benchmark]publicBigIntegerPowerOfTenPlusOne()=>BigInteger.Parse(s2);[Benchmark]publicBigIntegerPowerOfTenMinusOne()=>BigInteger.Parse(s3);}
BenchmarkDotNet v0.13.12, Windows 11 (10.0.22631.3527/23H2/2023Update/SunValley3)13th Gen Intel Core i5-13500, 1 CPU, 20 logical and 14 physical cores.NET SDK 9.0.100-preview.3.24204.13  [Host]     : .NET 9.0.0 (9.0.24.17209), X64 RyuJIT AVX2  Job-DWSMWG : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX2  Job-ECQBBV : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX2
MethodJobToolchainNMeanErrorStdDevRatioRatioSDCode SizeGen0AllocatedAlloc Ratio
PowerOfTenJob-DWSMWG\main\corerun.exe10005.022 μs0.0594 μs0.0496 μs1.000.002,909 B0.0305440 B1.00
PowerOfTenJob-ECQBBV\pr\corerun.exe10005.020 μs0.0969 μs0.0859 μs1.000.012,909 B0.0305440 B1.00
PowerOfTenJob-DWSMWG\main\corerun.exe10000404.471 μs7.6946 μs7.1975 μs1.000.002,902 B-4187 B1.00
PowerOfTenJob-ECQBBV\pr\corerun.exe1000068.792 μs1.3603 μs1.3970 μs0.170.002,877 B0.24414185 B1.00
PowerOfTenJob-DWSMWG\main\corerun.exe10000039,121.600 μs246.3455 μs205.7096 μs1.000.002,901 B-41612 B1.00
PowerOfTenJob-ECQBBV\pr\corerun.exe1000002,638.464 μs14.9664 μs13.2673 μs0.070.002,877 B-41579 B1.00
PowerOfTenJob-DWSMWG\main\corerun.exe10000004,009,495.647 μs17,321.2555 μs16,202.3132 μs1.000.0094 B-439056 B1.00
PowerOfTenJob-ECQBBV\pr\corerun.exe100000097,940.946 μs487.5769 μs432.2242 μs0.020.002,869 B-416352 B0.95
PowerOfTenPlusOneJob-DWSMWG\main\corerun.exe10005.881 μs0.0758 μs0.0592 μs1.000.002,909 B0.0305440 B1.00
PowerOfTenPlusOneJob-ECQBBV\pr\corerun.exe10005.841 μs0.0784 μs0.0733 μs0.990.012,877 B0.0305440 B1.00
PowerOfTenPlusOneJob-DWSMWG\main\corerun.exe10000278.657 μs1.8829 μs1.5723 μs1.000.002,877 B0.48838659 B1.00
PowerOfTenPlusOneJob-ECQBBV\pr\corerun.exe1000080.380 μs1.5721 μs1.4705 μs0.290.002,880 B0.24414184 B0.48
PowerOfTenPlusOneJob-DWSMWG\main\corerun.exe1000009,978.399 μs84.3427 μs78.8943 μs1.000.002,872 B-86136 B1.00
PowerOfTenPlusOneJob-ECQBBV\pr\corerun.exe1000003,041.650 μs13.5062 μs11.2783 μs0.300.002,870 B-41579 B0.48
PowerOfTenPlusOneJob-DWSMWG\main\corerun.exe1000000370,703.885 μs3,617.1873 μs3,020.5152 μs1.000.0094 B-866608 B1.00
PowerOfTenPlusOneJob-ECQBBV\pr\corerun.exe1000000112,643.729 μs870.3710 μs814.1455 μs0.300.002,872 B-416568 B0.48
PowerOfTenMinusOneJob-DWSMWG\main\corerun.exe10005.978 μs0.0465 μs0.0412 μs1.000.002,909 B0.0305440 B1.00
PowerOfTenMinusOneJob-ECQBBV\pr\corerun.exe10006.055 μs0.1183 μs0.1265 μs1.010.032,877 B0.0305440 B1.00
PowerOfTenMinusOneJob-DWSMWG\main\corerun.exe10000279.346 μs2.8043 μs2.3417 μs1.000.002,877 B0.48838659 B1.00
PowerOfTenMinusOneJob-ECQBBV\pr\corerun.exe10000208.960 μs1.3014 μs1.2173 μs0.750.012,877 B0.24414186 B0.48
PowerOfTenMinusOneJob-DWSMWG\main\corerun.exe10000010,202.449 μs58.1694 μs54.4117 μs1.000.002,872 B-86042 B1.00
PowerOfTenMinusOneJob-ECQBBV\pr\corerun.exe1000007,508.013 μs72.8591 μs64.5877 μs0.740.012,870 B-41613 B0.48
PowerOfTenMinusOneJob-DWSMWG\main\corerun.exe1000000367,924.436 μs2,814.6511 μs2,495.1149 μs1.000.0094 B-866560 B1.00
PowerOfTenMinusOneJob-ECQBBV\pr\corerun.exe1000000260,532.370 μs4,869.6777 μs4,555.0995 μs0.710.0194 B-415736 B0.48

PaulusParssinen reacted with rocket emoji
@ghostghost added community-contributionIndicates that the PR has been added by a community member area-System.Numerics labelsJan 27, 2024
@ghost
Copy link

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

Issue Details

BigInteger.Parse("1" + new string('0', n)) is too slow. It runs in$O(n^2)$.
This is because trailing zeros are always calculated naively.
I fixed the behavior.

Benchmark

usingBenchmarkDotNet.Attributes;usingBenchmarkDotNet.Running;usingSystem.Numerics;usingSystem.Runtime.InteropServices;BenchmarkSwitcher.FromAssembly(typeof(Tests).Assembly).Run(args);[DisassemblyDiagnoser]publicclassTests{[Params(1000,10000,100000,1000000)]publicintN;strings1,s2,s3;[GlobalSetup]publicvoidSetup(){s1="1"+newstring('0',N);s2="1"+newstring('0',N-1)+"1";s3=newstring('9',N-1);}[Benchmark]publicBigIntegerPowerOfTen()=>BigInteger.Parse(s1);[Benchmark(Baseline=true)]publicBigIntegerPowerOfTenPlusOne()=>BigInteger.Parse(s2);[Benchmark]publicBigIntegerPowerOfTenMinusOne()=>BigInteger.Parse(s3);}
BenchmarkDotNet v0.13.12, Windows 11 (10.0.22631.3085/23H2/2023Update/SunValley3)13th Gen Intel Core i5-13500, 1 CPU, 20 logical and 14 physical cores.NET SDK 9.0.100-alpha.1.23615.4  [Host]     : .NET 9.0.0 (9.0.23.61410), X64 RyuJIT AVX2  Job-KEBJOQ : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX2  Job-VLAEBK : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX2
MethodJobToolchainNMeanErrorStdDevRatioRatioSDCode SizeGen0AllocatedAlloc Ratio
PowerOfTenJob-KEBJOQ\main\corerun.exe10005.464 μs0.0769 μs0.0720 μs0.880.013,216 B0.0305440 B1.00
PowerOfTenPlusOneJob-KEBJOQ\main\corerun.exe10006.200 μs0.0829 μs0.0775 μs1.000.003,216 B0.0305440 B1.00
PowerOfTenMinusOneJob-KEBJOQ\main\corerun.exe10005.965 μs0.0475 μs0.0444 μs0.960.013,216 B0.0305440 B1.00
PowerOfTenJob-VLAEBK\pr\corerun.exe10005.728 μs0.0488 μs0.0456 μs0.920.013,309 B0.0763976 B2.22
PowerOfTenPlusOneJob-VLAEBK\pr\corerun.exe10006.172 μs0.0492 μs0.0460 μs1.000.013,309 B0.0763976 B2.22
PowerOfTenMinusOneJob-VLAEBK\pr\corerun.exe10005.778 μs0.0388 μs0.0344 μs0.930.013,309 B0.0763976 B2.22
PowerOfTenJob-KEBJOQ\main\corerun.exe10000425.126 μs6.6050 μs6.1783 μs0.980.023,216 B-4184 B1.00
PowerOfTenPlusOneJob-KEBJOQ\main\corerun.exe10000433.456 μs6.0261 μs5.6369 μs1.000.003,216 B-4184 B1.00
PowerOfTenMinusOneJob-KEBJOQ\main\corerun.exe10000432.347 μs3.8901 μs3.6388 μs1.000.023,216 B-4177 B1.00
PowerOfTenJob-VLAEBK\pr\corerun.exe10000424.032 μs6.4220 μs6.0071 μs0.980.023,309 B0.976612400 B2.96
PowerOfTenPlusOneJob-VLAEBK\pr\corerun.exe10000434.967 μs5.7997 μs5.4250 μs1.000.023,309 B0.976612400 B2.96
PowerOfTenMinusOneJob-VLAEBK\pr\corerun.exe10000429.771 μs5.5313 μs5.1740 μs0.990.023,305 B0.976612392 B2.96
PowerOfTenJob-KEBJOQ\main\corerun.exe10000041,307.777 μs380.6849 μs356.0929 μs3.670.083,216 B-41583 B0.48
PowerOfTenPlusOneJob-KEBJOQ\main\corerun.exe10000011,274.413 μs215.6506 μs211.7977 μs1.000.002,954 B-86046 B1.00
PowerOfTenMinusOneJob-KEBJOQ\main\corerun.exe10000011,382.852 μs214.8872 μs201.0056 μs1.010.032,954 B-86041 B1.00
PowerOfTenJob-VLAEBK\pr\corerun.exe1000004,972.020 μs73.2368 μs68.5057 μs0.440.013,047 B7.8125107118 B1.24
PowerOfTenPlusOneJob-VLAEBK\pr\corerun.exe1000005,093.083 μs56.5632 μs52.9092 μs0.450.013,047 B-41556 B0.48
PowerOfTenMinusOneJob-VLAEBK\pr\corerun.exe10000010,432.147 μs116.1019 μs108.6018 μs0.930.023,047 B-41564 B0.48
PowerOfTenJob-KEBJOQ\main\corerun.exe10000004,151,269.093 μs43,494.0408 μs40,684.3528 μs10.460.1494 B-415720 B0.48
PowerOfTenPlusOneJob-KEBJOQ\main\corerun.exe1000000396,808.680 μs6,230.0066 μs5,827.5520 μs1.000.0094 B-860144 B1.00
PowerOfTenMinusOneJob-KEBJOQ\main\corerun.exe1000000395,750.933 μs7,009.0187 μs6,556.2404 μs1.000.0294 B-860864 B1.00
PowerOfTenJob-VLAEBK\pr\corerun.exe1000000199,223.140 μs2,441.7662 μs2,284.0296 μs0.500.013,047 B-939717 B1.09
PowerOfTenPlusOneJob-VLAEBK\pr\corerun.exe1000000196,380.902 μs2,521.1383 μs2,358.2743 μs0.500.013,047 B-415517 B0.48
PowerOfTenMinusOneJob-VLAEBK\pr\corerun.exe1000000376,507.469 μs3,501.7144 μs2,924.0902 μs0.950.0194 B-416008 B0.48
Author:kzrnm
Assignees:-
Labels:

area-System.Numerics,community-contribution

Milestone:-

@kzrnm
Copy link
ContributorAuthor

I updated the benchmark target to the latest commit.

tannergooding reacted with thumbs up emoji

@tannergooding
Copy link
Member

I updated the benchmark target to the latest commit.

Thanks! Slowly getting through stuff here and just want to ensure no conflicts/accurate numbers/etc as they go through.

@tannergooding
Copy link
Member

Looks like there are some related CI failures that need to get resolved.

@kzrnm
Copy link
ContributorAuthor

Tests fail whenparseTest andToStringTest are run in parallel. I thinkRunWithFakeThreshold is the cause of failure.
I setDisableParallelization so thatRunWithFakeThreshold is not executed in parallel.

@kzrnm
Copy link
ContributorAuthor

I was able to reproduce the error with the following code.

Number.s_naiveThreshold=0;BigInteger.Parse("99000000000");

@tannergooding
Copy link
Member

@huoyaoyuan, if you have some time I'd appreciate if you could give this a once over as well, given you've also been touching/updating the parsing logic.

I'd ideally like to get#95402 done first and I know there's another PR out, but you recently changed that one back todraft

@huoyaoyuan
Copy link
Member

I'd ideally like to get #95402 done first and I know there's another PR out, but you recently changed that one back to draft

I've done the code update and measuring the performance. I'd expect to make it ready this weekend.

@kzrnmkzrnmforce-pushed theBigIntegerParsePowOf10 branch fromdfde2c5 tod69b10aCompareFebruary 5, 2024 18:02
@kzrnmkzrnm changed the titleOptimize BigInteger.Parse(powerOfTen)Optimize BigInteger.ParseFeb 15, 2024
@kzrnmkzrnmforce-pushed theBigIntegerParsePowOf10 branch from1da8f28 toedc6a57CompareFebruary 16, 2024 11:22
@kzrnmkzrnmforce-pushed theBigIntegerParsePowOf10 branch from3daff74 to9f5f44aCompareFebruary 16, 2024 17:04
kzrnm added6 commitsMay 6, 2024 03:15
# Conflicts:#src/libraries/System.Runtime.Numerics/src/System/Numerics/BigIntegerCalculator.SquMul.cs#src/libraries/System.Runtime.Numerics/tests/BigInteger/multiply.cs
@kzrnmkzrnmforce-pushed theBigIntegerParsePowOf10 branch fromd785168 to456bf8eCompareMay 12, 2024 17:37
@kzrnmkzrnmforce-pushed theBigIntegerParsePowOf10 branch fromf92dff4 to29747f2CompareMay 14, 2024 16:32
@tannergooding
Copy link
Member

@kzrnm, sorry for the delay on this. Could you share updated numbers, just so we can confirm nothing has regressed given all the other work that's been done?

After that, I think we can get this merged.

@kzrnm
Copy link
ContributorAuthor

@tannergooding I ran benchmarks on the latest branch.

BenchmarkDotNet v0.13.12, Windows 11 (10.0.22631.3810/23H2/2023Update/SunValley3)13th Gen Intel Core i5-13500, 1 CPU, 20 logical and 14 physical cores.NET SDK 9.0.100-preview.5.24307.3  [Host]   : .NET 9.0.0 (9.0.24.30607), X64 RyuJIT AVX2  ShortRun : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX2Job=ShortRun  IterationCount=3  LaunchCount=1  WarmupCount=3
MethodToolchainNMeanErrorStdDevRatioRatioSDGen0Code SizeAllocatedAlloc Ratio
PowerOfTen\main\corerun.exe10004.723 μs0.7022 μs0.0385 μs1.000.000.03053,051 B440 B1.00
PowerOfTen\pr\corerun.exe10004.727 μs0.2059 μs0.0113 μs1.000.010.03053,051 B440 B1.00
PowerOfTen\main\corerun.exe10000417.409 μs85.4963 μs4.6863 μs1.000.00-3,049 B4185 B1.00
PowerOfTen\pr\corerun.exe1000065.805 μs2.0472 μs0.1122 μs0.160.000.24413,019 B4184 B1.00
PowerOfTen\main\corerun.exe10000039,509.697 μs7,036.3549 μs385.6864 μs1.000.00-3,048 B41634 B1.00
PowerOfTen\pr\corerun.exe1000002,621.521 μs445.6280 μs24.4264 μs0.070.00-3,016 B41556 B1.00
PowerOfTen\main\corerun.exe10000005,547,848.100 μs44,683.6720 μs2,449.2628 μs1.000.00-94 B416344 B1.00
PowerOfTen\pr\corerun.exe1000000106,203.493 μs35,159.8003 μs1,927.2273 μs0.020.00-94 B415486 B1.00
PowerOfTenPlusOne\main\corerun.exe10005.631 μs0.2055 μs0.0113 μs1.000.000.03053,049 B440 B1.00
PowerOfTenPlusOne\pr\corerun.exe10005.309 μs0.1675 μs0.0092 μs0.940.000.03053,019 B440 B1.00
PowerOfTenPlusOne\main\corerun.exe10000287.339 μs16.9327 μs0.9281 μs1.000.000.48833,017 B8657 B1.00
PowerOfTenPlusOne\pr\corerun.exe1000076.457 μs8.4699 μs0.4643 μs0.270.000.24413,017 B4184 B0.48
PowerOfTenPlusOne\main\corerun.exe10000010,017.519 μs2,451.2130 μs134.3593 μs1.000.00-3,016 B86046 B1.00
PowerOfTenPlusOne\pr\corerun.exe1000003,088.058 μs581.6661 μs31.8831 μs0.310.00-3,017 B41556 B0.48
PowerOfTenPlusOne\main\corerun.exe1000000371,023.767 μs47,955.9585 μs2,628.6279 μs1.000.00-94 B860864 B1.00
PowerOfTenPlusOne\pr\corerun.exe1000000117,715.373 μs38,234.2942 μs2,095.7507 μs0.320.00-94 B415429 B0.48
PowerOfTenMinusOne\main\corerun.exe10005.784 μs0.7608 μs0.0417 μs1.000.000.03053,051 B440 B1.00
PowerOfTenMinusOne\pr\corerun.exe10005.551 μs0.5350 μs0.0293 μs0.960.010.03053,018 B440 B1.00
PowerOfTenMinusOne\main\corerun.exe10000296.562 μs88.8331 μs4.8692 μs1.000.000.48833,017 B8657 B1.00
PowerOfTenMinusOne\pr\corerun.exe10000208.304 μs79.8736 μs4.3781 μs0.700.020.24413,019 B4184 B0.48
PowerOfTenMinusOne\main\corerun.exe10000010,168.222 μs1,159.4629 μs63.5541 μs1.000.00-3,016 B86046 B1.00
PowerOfTenMinusOne\pr\corerun.exe1000007,655.886 μs1,894.1289 μs103.8236 μs0.750.01-3,017 B41560 B0.48
PowerOfTenMinusOne\main\corerun.exe1000000366,404.433 μs47,445.9123 μs2,600.6706 μs1.000.00-94 B860864 B1.00
PowerOfTenMinusOne\pr\corerun.exe1000000263,400.400 μs50,544.4774 μs2,770.5134 μs0.720.01-94 B415808 B0.48

@tannergoodingtannergooding merged commit7a5fb4f intodotnet:mainJul 3, 2024
83 checks passed
@kzrnmkzrnm deleted the BigIntegerParsePowOf10 branchJuly 4, 2024 00:58
@LoopedBard3
Copy link
Member

LoopedBard3 commentedJul 9, 2024
edited
Loading

@tannergooding
Copy link
Member

Just noting on the regressions above that many of them are for very small inputs, like123. I've raised that these aren't "representative" of the cases we care about here since if users care about perf for numbers that are less than or equal to 128-bits, then we have existing dedicated types they can use.

Rather, we want to ensure thatBigInteger really shines for values above this cutoff. -- There is notably some consideration that we also don't want to overly regress the perf of BigInteger values with 128 or less bits, just that its not as important. For a case likeParse we could likely have a fast path that does something likeif (stringLength < 40) { ParseAsInt128 } else { ParseAsBigInt }, since any string with this few digits must fit into Int128 (and a corresponding cutoff for hex numbers, etc). This would likely fix the regression without hurting the improved cases.

Sign up for freeto subscribe to this conversation on GitHub. Already have an account?Sign in.
Reviewers

@tannergoodingtannergoodingtannergooding approved these changes

Assignees
No one assigned
Labels
area-System.Numericscommunity-contributionIndicates that the PR has been added by a community member
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

4 participants
@kzrnm@tannergooding@huoyaoyuan@LoopedBard3

[8]ページ先頭

©2009-2025 Movatter.jp