Add Decimal32, Decimal64, Decimal128#100729
Conversation
|
Note regarding the |
src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs
Outdated
Show resolved
Hide resolved
| static int IDecimalIeee754UnpackInfo<Decimal128, Int128, UInt128>.NumberDigitsPrecision => NumberDigitsPrecision; | ||
|
|
||
|
|
||
| private static Int128[] Int128Powers10 => |
There was a problem hiding this comment.
If Int128 is not optimized, this can be optimally stored as a ReadOnlySpan of Int32/Int64 like Number.BigInteger.Pow10BigNumTable
| public override int GetHashCode() | ||
| { | ||
| return _value.GetHashCode(); | ||
| } |
There was a problem hiding this comment.
+0 and -0 should have the same hash code. The easiest way can be stripping the sign bit.
I also remember that there can be same values with different representations.
There was a problem hiding this comment.
@huoyaoyuan Thanks for your review. However this PR targets only the first phase as following: #81376 (comment) so I haven't added NegativeZero and PositiveZero. I will update GetHashCode method in the next phase.
src/libraries/System.Private.CoreLib/src/System/Numerics/Decimal128.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.cs
Outdated
Show resolved
Hide resolved
|
This is on my radar to take a look at; just noting it might be a bit delayed due to other priorities for the .NET 9 release. CC. @jeffhandley |
| private static readonly UInt128 PositiveInfinityValue = new UInt128(upper: 0x7800_0000_0000_0000, lower: 0); | ||
| private static readonly UInt128 NegativeInfinityValue = new UInt128(upper: 0xf800_0000_0000_0000, lower: 0); | ||
| private static readonly UInt128 ZeroValue = new UInt128(0, 0); | ||
| private static readonly UInt128 NegativeZeroValue = new UInt128(0x8000_0000_0000_0000, 0); |
There was a problem hiding this comment.
Can this be a problem for codegen since UInt128 is not const?
There was a problem hiding this comment.
They should probably be properties instead
There was a problem hiding this comment.
Thanks, I have updated it.
| return Number.FormatDecimalIeee754<Decimal128, UInt128>(this, format, NumberFormatInfo.GetInstance(provider)); | ||
| } | ||
|
|
||
| private static UInt128[] UInt128Powers10 => |
There was a problem hiding this comment.
This can be a problem for constant embedding. long array can be encoded into executable and read by pairs.
|
Are there any preliminary benchmarks of these new types? I.e. How do Also, can we expect these new types to arrive in |
We are focusing on the different semantic first. Both types are having different existing standard to follow.
It's optimistic, but not a guarantee. |
|
Hi @tannergooding, thanks for your review, I have resolved almost your comments (handle NaN, |
|
Hi @tannergooding can you help me take a look at this PR when you have time 😉 |
|
Yes, this is still on my backlog, just had some other work items that have been higher priority. Sorry for the delay |
|
@RaymondHuy Just reassuring you this is still on our radar. We are committed to getting this into .NET 11 as early in the release as we can. |
src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Decimal32Tests.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Decimal128Tests.cs
Outdated
Show resolved
Hide resolved
| private static UInt128 NegativeZeroValue => new UInt128(0x8000_0000_0000_0000, 0); | ||
| private static UInt128 QuietNaNValue => new UInt128(0x7C00_0000_0000_0000, 0); | ||
| private static UInt128 MaxInternalValue = new UInt128(upper: 0x5FFF_ED09_BEAD_87C0, lower: 0x378D_8E63_FFFF_FFFF); | ||
| private static UInt128 MinInternalValue = new UInt128(upper: 0xDFFF_ED09B_EAD_87C0, lower: 0x378D_8E63_FFFF_FFFF); |
There was a problem hiding this comment.
There appears to be a typo in the hexadecimal constant. The value 0xDFFF_ED09B_EAD_87C0 contains an extra 'B' after '09'. It should likely be 0xDFFF_ED09_BEAD_87C0 to match the pattern in MaxInternalValue on line 39.
| private static UInt128 MinInternalValue = new UInt128(upper: 0xDFFF_ED09B_EAD_87C0, lower: 0x378D_8E63_FFFF_FFFF); | |
| private static UInt128 MinInternalValue = new UInt128(upper: 0xDFFF_ED09_BEAD_87C0, lower: 0x378D_8E63_FFFF_FFFF); |
src/libraries/System.Private.CoreLib/src/System/Numerics/Decimal128.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Decimal32Tests.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Decimal64Tests.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Decimal128Tests.cs
Outdated
Show resolved
Hide resolved
| 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]; |
There was a problem hiding this comment.
The bit shift operation ((ulong)(_blocks[3]) << 96) is incorrect. A ulong is 64 bits, so shifting it by 96 bits will produce 0 or undefined behavior. For a UInt128 with blocks stored as 32-bit values, the upper bits should be constructed differently. The correct approach should be: new UInt128(((ulong)_blocks[3] << 32) + _blocks[2], ((ulong)_blocks[1] << 32) + _blocks[0]) since UInt128 takes two ulong parameters (upper and lower 64 bits).
| 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]; | |
| return new UInt128(((ulong)_blocks[3] << 32) + _blocks[2], ((ulong)_blocks[1] << 32) + _blocks[0]); | |
| } | |
| if (_length > 2) | |
| { | |
| return new UInt128(_blocks[2], ((ulong)_blocks[1] << 32) + _blocks[0]); | |
| } | |
| if (_length > 1) | |
| { | |
| return ((ulong)_blocks[1] << 32) + _blocks[0]; |
|
@RaymondHuy Copilot's review produced some good feedback comments. The using statements and unused variables look straightforward enough, but the bit-shifting comment warrants your analysis and consideration, so I've left all those comments unaddressed. |
|
Hi @jeffhandley , thanks for your review, I have resolved all of them and also added test case to bit-shifting comment. |
Resolve #81376