Skip to content

Add Decimal32, Decimal64, Decimal128 #100729

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

Open
wants to merge 54 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
ac5e447
add constructor info
RaymondHuy Mar 11, 2024
1af3337
Add Decimal32
RaymondHuy Mar 30, 2024
cee05c8
add test cases
RaymondHuy Apr 5, 2024
da72dcd
Add Decimal128
RaymondHuy Apr 6, 2024
6f3827c
add tests
RaymondHuy Apr 6, 2024
7e9344b
Merge commit '83b0d939bedadf7d782b0b26307c2d8c1d5b76f4' into issue-81376
RaymondHuy Apr 7, 2024
f882b96
Fix digits pointer
RaymondHuy Apr 7, 2024
762f56d
Implement ToString() method.
RaymondHuy Apr 9, 2024
66a1127
resolve comments
RaymondHuy Apr 9, 2024
83937d2
resolve comments
RaymondHuy Apr 9, 2024
19755ba
Refactor shift operators to mask
RaymondHuy Apr 10, 2024
ede6ca3
Extract common mask to property.
RaymondHuy Apr 10, 2024
b4e5d34
add more tests
RaymondHuy Apr 10, 2024
504f042
add comments
RaymondHuy Apr 11, 2024
31ffd5c
Add overflow message.
RaymondHuy Apr 11, 2024
6212873
Add overflow message
RaymondHuy Apr 11, 2024
cb1d8b1
split uint128 to ulong.
RaymondHuy Apr 11, 2024
0a4620e
Change private to internal
RaymondHuy Apr 11, 2024
8f3d4ff
validate overflow decimal case.
RaymondHuy Apr 12, 2024
db834cb
add more tests
RaymondHuy Apr 18, 2024
2ed126b
add more tests
RaymondHuy May 29, 2024
d08b7b5
add more tests
RaymondHuy May 29, 2024
bcfdca6
Merge branch 'master' into issue-81376
RaymondHuy Nov 13, 2024
472a2fe
Merge branch 'master' into issue-81376
RaymondHuy Nov 22, 2024
49f6676
Correct naming
RaymondHuy Dec 17, 2024
f82d9a6
fix naming convention
RaymondHuy Dec 17, 2024
567906c
Merge branch 'main' into issue-81376
tannergooding Jan 30, 2025
70cc09d
Merge branch 'main' into issue-81376
RaymondHuy Mar 5, 2025
715677f
Merge branch 'main' into issue-81376
RaymondHuy Mar 14, 2025
a66d209
Merge branch 'main' into issue-81376
RaymondHuy Mar 20, 2025
2405a15
Merge branch 'main' into issue-81376
RaymondHuy Mar 24, 2025
926db20
Merge branch 'main' into issue-81376
RaymondHuy Mar 30, 2025
d41c56e
Merge branch 'main' into issue-81376
RaymondHuy Apr 3, 2025
ac8f7a6
resolve simple comments
RaymondHuy Apr 4, 2025
9d0fa8e
combine interface
RaymondHuy Apr 4, 2025
4478f54
add XML documentation
RaymondHuy Apr 4, 2025
7b1db43
add XML documentation
RaymondHuy Apr 4, 2025
79bea65
resolve comments
RaymondHuy Apr 4, 2025
e9a5cf7
Revert "resolve comments"
RaymondHuy Apr 4, 2025
0a57a1a
resolve comments
RaymondHuy Apr 4, 2025
ab7c5fb
resolve comments.
RaymondHuy Apr 5, 2025
6a1c2c3
remove unused fields.
RaymondHuy Apr 5, 2025
e584a92
use ArrayPool
RaymondHuy Apr 8, 2025
84ef494
add comments
RaymondHuy Apr 8, 2025
61eaba8
remove constructor
RaymondHuy Apr 15, 2025
2a1fc70
remove constructor
RaymondHuy Apr 15, 2025
afc15e4
add rounding method
RaymondHuy Apr 20, 2025
002d9dd
Merge branch 'main' into issue-81376
RaymondHuy Apr 20, 2025
0d598a2
add digit count condition check
RaymondHuy Apr 24, 2025
313c90d
fix wrong rounding
RaymondHuy Apr 24, 2025
7b6a3c0
correct last significand digit.
RaymondHuy Apr 24, 2025
d93ac2b
add comments
RaymondHuy Apr 24, 2025
c44003e
add more tests
RaymondHuy Apr 25, 2025
9533b39
remove unused test cases
RaymondHuy Apr 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/libraries/Common/src/System/Number.NumberBuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ internal static partial class Number
internal const int UInt32NumberBufferLength = 10 + 1; // 10 for the longest input: 4,294,967,295
internal const int UInt64NumberBufferLength = 20 + 1; // 20 for the longest input: 18,446,744,073,709,551,615
internal const int UInt128NumberBufferLength = 39 + 1; // 39 for the longest input: 340,282,366,920,938,463,463,374,607,431,768,211,455
internal const int Decimal32NumberBufferLength = 97 + 1 + 1; // 97 for the longest input + 1 for rounding
internal const int Decimal64NumberBufferLength = 385 + 1 + 1; // 385 for the longest input + 1 for rounding
internal const int Decimal128NumberBufferLength = 6145 + 1 + 1; // 6145 for the longest input + 1 for rounding
Comment on lines +24 to +26
Copy link
Member

Choose a reason for hiding this comment

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

A comment explaining why these numbers are correct would be beneficial.

There's many resources out there that break down the algorithm for how you get to 767 digits for the longest double (or 11563 for binary128), as it is:

MaxUnbiasedExponent + ⌊log10((2^SignificandBits – 1) /  2^MaxUnbiasedExponent)⌋ + 1 

But the algorithm for decimal isn't as well known (but should overall be similar).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi @tannergooding , I have tried your formula but I can't get the 767 result.
MaxUnbiasedExponent = 1023, SignificandBits = 52
result is 1023 + (−309) + 1= 715.

Copy link
Member

@tannergooding tannergooding Apr 8, 2025

Choose a reason for hiding this comment

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

Sorry, I did it from memory initially. It should be (MaxUnbiasedExponent + TrailingSignificandBits - 1)

So for double it is 1074 + ⌊log10((2^53 – 1) / 2^1074)⌋ + 1. This is because the largest subnormal expands to a value that is 1074 digits in length (which is why in many comments and other places you'll see 1074 and 1075 being used)


internal unsafe ref struct NumberBuffer
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,15 @@
<data name="Arg_MustBeDecimal" xml:space="preserve">
<value>Object must be of type Decimal.</value>
</data>
<data name="Arg_MustBeDecimal32" xml:space="preserve">
<value>Object must be of type Decimal32.</value>
</data>
<data name="Arg_MustBeDecimal64" xml:space="preserve">
<value>Object must be of type Decimal64.</value>
</data>
<data name="Arg_MustBeDecimal128" xml:space="preserve">
<value>Object must be of type Decimal128.</value>
</data>
<data name="Arg_MustBeDelegate" xml:space="preserve">
<value>Type must derive from Delegate.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,10 @@
<Compile Include="$(MSBuildThisFileDirectory)System\IFormatProvider.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IFormattable.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Index.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Number.DecimalIeee754.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Numerics\Decimal128.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Numerics\Decimal32.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Numerics\Decimal64.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\Any1CharPackedSearchValues.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\Any1CharPackedIgnoreCaseSearchValues.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\Any2CharPackedIgnoreCaseSearchValues.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1324,6 +1324,31 @@ public ulong ToUInt64()
return 0;
}

public UInt128 ToUInt128()
{
if (_length > 3)
{
return new UInt128(((ulong)(_blocks[3]) << 96) + ((ulong)_blocks[2] << 64), ((ulong)(_blocks[1]) << 32) + _blocks[0]);
}

if (_length > 2)
{
return new UInt128(((ulong)_blocks[2] << 64), ((ulong)(_blocks[1]) << 32) + _blocks[0]);
}

if (_length > 1)
{
return ((ulong)(_blocks[1]) << 32) + _blocks[0];
}

if (_length > 0)
{
return _blocks[0];
}

return 0;
}

private void Clear(uint length) =>
NativeMemory.Clear(
(byte*)Unsafe.AsPointer(ref _blocks[0]), // This is safe to do since we are a ref struct
Expand Down
Loading
Loading