Skip to content

Commit 621ad66

Browse files
Fix FormattingHelpers.CountDigits(UInt128) and add more tests for Int128/UInt128.ToString (#74536)
Co-authored-by: Tanner Gooding <[email protected]>
1 parent 66173b4 commit 621ad66

File tree

3 files changed

+33
-4
lines changed

3 files changed

+33
-4
lines changed

src/libraries/System.Private.CoreLib/src/System/Buffers/Text/FormattingHelpers.CountDigits.cs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,37 @@ public static int CountDigits(UInt128 value)
1414
{
1515
ulong upper = value.Upper;
1616

17-
if (upper < 5)
17+
// 1e19 is 8AC7_2304_89E8_0000
18+
// 1e20 is 5_6BC7_5E2D_6310_0000
19+
// 1e21 is 36_35C9_ADC5_DEA0_0000
20+
21+
if (upper == 0)
1822
{
23+
// We have less than 64-bits, so just return the lower count
1924
return CountDigits(value.Lower);
2025
}
2126

22-
int digits = 19;
27+
// We have more than 1e19, so we have at least 20 digits
28+
int digits = 20;
2329

2430
if (upper > 5)
2531
{
26-
digits++;
32+
// ((2^128) - 1) / 1e20 < 34_02_823_669_209_384_635 which
33+
// is 18.5318 digits, meaning the result definitely fits
34+
// into 64-bits and we only need to add the lower digit count
35+
2736
value /= new UInt128(0x5, 0x6BC7_5E2D_6310_0000); // value /= 1e20
37+
Debug.Assert(value.Upper == 0);
38+
2839
digits += CountDigits(value.Lower);
2940
}
30-
else if (value.Lower >= 0x6BC75E2D63100000)
41+
else if ((upper == 5) && (value.Lower >= 0x6BC75E2D63100000))
3142
{
43+
// We're greater than 1e20, but definitely less than 1e21
44+
// so we have exactly 21 digits
45+
3246
digits++;
47+
Debug.Assert(digits == 21);
3348
}
3449

3550
return digits;

src/libraries/System.Runtime/tests/System/Int128Tests.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,12 @@ public static IEnumerable<object[]> ToString_TestData()
116116
yield return new object[] { (Int128)(-4567), defaultSpecifier, defaultFormat, "-4567" };
117117
yield return new object[] { (Int128)0, defaultSpecifier, defaultFormat, "0" };
118118
yield return new object[] { (Int128)4567, defaultSpecifier, defaultFormat, "4567" };
119+
yield return new object[] { new Int128(0x0000_0000_0000_0001, 0x0000_0000_0000_0003), defaultSpecifier, defaultFormat, "18446744073709551619" };
120+
yield return new object[] { new Int128(0x0000_0000_0000_0001, 0x0000_0000_0000_000A), defaultSpecifier, defaultFormat, "18446744073709551626" };
121+
yield return new object[] { new Int128(0x0000_0000_0000_0005, 0x0000_0000_0000_0001), defaultSpecifier, defaultFormat, "92233720368547758081" };
122+
yield return new object[] { new Int128(0x0000_0000_0000_0005, 0x6BC7_5E2D_6310_0000), defaultSpecifier, defaultFormat, "100000000000000000000" };
123+
yield return new object[] { new Int128(0x0000_0000_0000_0036, 0x35C9_ADC5_DEA0_0000), defaultSpecifier, defaultFormat, "1000000000000000000000" };
124+
yield return new object[] { new Int128(0x0013_4261_72C7_4D82, 0x2B87_8FE8_0000_0000), defaultSpecifier, defaultFormat, "100000000000000000000000000000000000" };
119125
yield return new object[] { Int128.MaxValue, defaultSpecifier, defaultFormat, "170141183460469231731687303715884105727" };
120126
}
121127

src/libraries/System.Runtime/tests/System/UInt128Tests.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,14 @@ public static IEnumerable<object[]> ToString_TestData()
101101
{
102102
yield return new object[] { (UInt128)0, defaultSpecifier, defaultFormat, "0" };
103103
yield return new object[] { (UInt128)4567, defaultSpecifier, defaultFormat, "4567" };
104+
yield return new object[] { new UInt128(0x0000_0000_0000_0001, 0x0000_0000_0000_0003), defaultSpecifier, defaultFormat, "18446744073709551619" };
105+
yield return new object[] { new UInt128(0x0000_0000_0000_0001, 0x0000_0000_0000_000A), defaultSpecifier, defaultFormat, "18446744073709551626" };
106+
yield return new object[] { new UInt128(0x0000_0000_0000_0005, 0x0000_0000_0000_0001), defaultSpecifier, defaultFormat, "92233720368547758081" };
107+
yield return new object[] { new UInt128(0x0000_0000_0000_0005, 0x6BC7_5E2D_6310_0000), defaultSpecifier, defaultFormat, "100000000000000000000" };
108+
yield return new object[] { new UInt128(0x0000_0000_0000_0036, 0x35C9_ADC5_DEA0_0000), defaultSpecifier, defaultFormat, "1000000000000000000000" };
109+
yield return new object[] { new UInt128(0x0013_4261_72C7_4D82, 0x2B87_8FE8_0000_0000), defaultSpecifier, defaultFormat, "100000000000000000000000000000000000" };
110+
yield return new object[] { new UInt128(0x7FFF_FFFF_FFFF_FFFF, 0xFFFF_FFFF_FFFF_FFFF), defaultSpecifier, defaultFormat, "170141183460469231731687303715884105727" };
111+
yield return new object[] { new UInt128(0x8000_0000_0000_0000, 0x0000_0000_0000_0000), defaultSpecifier, defaultFormat, "170141183460469231731687303715884105728" };
104112
yield return new object[] { UInt128.MaxValue, defaultSpecifier, defaultFormat, "340282366920938463463374607431768211455" };
105113
}
106114

0 commit comments

Comments
 (0)