-
Notifications
You must be signed in to change notification settings - Fork 5.3k
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
base: main
Are you sure you want to change the base?
Changes from 7 commits
ac5e447
1af3337
cee05c8
da72dcd
6f3827c
7e9344b
f882b96
762f56d
66a1127
83937d2
19755ba
ede6ca3
b4e5d34
504f042
31ffd5c
6212873
cb1d8b1
0a4620e
8f3d4ff
db834cb
2ed126b
d08b7b5
bcfdca6
472a2fe
49f6676
f82d9a6
567906c
70cc09d
715677f
a66d209
2405a15
926db20
d41c56e
ac8f7a6
9d0fa8e
4478f54
7b1db43
79bea65
e9a5cf7
0a57a1a
ab7c5fb
6a1c2c3
e584a92
84ef494
61eaba8
2a1fc70
afc15e4
002d9dd
0d598a2
313c90d
7b6a3c0
d93ac2b
c44003e
9533b39
f2e73e2
e2b497a
a1dee7b
0ce3024
a136ca1
335089f
e34d256
6947fe1
d17a6d3
b4c97a5
eb07b42
5a1a8fe
516a200
bdf86f5
1921014
ee2acad
a9362e3
8668878
3f7be57
cef4924
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,252 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System.Numerics; | ||
|
|
||
| namespace System | ||
| { | ||
| internal interface IDecimalIeee754ConstructorInfo<TSelf, TSignificand, TValue> | ||
| where TSelf : unmanaged, IDecimalIeee754ConstructorInfo<TSelf, TSignificand, TValue> | ||
| where TSignificand : IBinaryInteger<TSignificand> | ||
| where TValue : IBinaryInteger<TValue> | ||
| { | ||
| static abstract TSignificand MaxSignificand { get; } | ||
| static abstract int MaxDecimalExponent { get; } | ||
| static abstract int MinDecimalExponent { get; } | ||
| static abstract int NumberDigitsPrecision { get; } | ||
| static abstract int Bias { get; } | ||
RaymondHuy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| static abstract int CountDigits(TSignificand number); | ||
| static abstract TSignificand Power10(int exponent); | ||
| static abstract int MostSignificantBitNumberOfSignificand { get; } | ||
| static abstract int NumberBitsEncoding { get; } | ||
| static abstract int NumberBitsCombinationField { get; } | ||
| static abstract int NumberBitsExponent { get; } | ||
| static abstract TValue PositiveInfinityBits { get; } | ||
| static abstract TValue NegativeInfinityBits { get; } | ||
| static abstract TValue Zero { get; } | ||
| } | ||
|
|
||
| internal interface IDecimalIeee754UnpackInfo<TSelf, TSignificand, TValue> | ||
RaymondHuy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| where TSelf : unmanaged, IDecimalIeee754UnpackInfo<TSelf, TSignificand, TValue> | ||
| where TSignificand : IBinaryInteger<TSignificand> | ||
| where TValue : IBinaryInteger<TValue> | ||
| { | ||
| static abstract TValue SignMask { get; } | ||
| static abstract int NumberBitsEncoding { get; } | ||
| static abstract int NumberBitsExponent { get; } | ||
| static abstract int NumberDigitsPrecision { get; } | ||
| static abstract int Bias { get; } | ||
| static abstract TSignificand TwoPowerMostSignificantBitNumberOfSignificand { get; } | ||
| static abstract int ConvertToExponent(TValue value); | ||
| static abstract TSignificand ConvertToSignificand(TValue value); | ||
| static abstract TSignificand Power10(int exponent); | ||
| } | ||
|
|
||
| internal static partial class Number | ||
| { | ||
| internal static TValue CalDecimalIeee754<TDecimal, TSignificand, TValue>(TSignificand significand, int exponent) | ||
RaymondHuy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| where TDecimal : unmanaged, IDecimalIeee754ConstructorInfo<TDecimal, TSignificand, TValue> | ||
| where TSignificand : IBinaryInteger<TSignificand> | ||
| where TValue : IBinaryInteger<TValue> | ||
| { | ||
| if (significand == TSignificand.Zero) | ||
RaymondHuy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| { | ||
| return TValue.Zero; | ||
| } | ||
|
|
||
| TSignificand unsignedSignificand = significand > TSignificand.Zero ? significand : -significand; | ||
RaymondHuy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| if (unsignedSignificand > TDecimal.MaxSignificand && exponent > TDecimal.MaxDecimalExponent) | ||
| { | ||
| return significand > TSignificand.Zero ? TDecimal.PositiveInfinityBits : TDecimal.NegativeInfinityBits; | ||
RaymondHuy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| TSignificand ten = TSignificand.CreateTruncating(10); | ||
RaymondHuy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (exponent < TDecimal.MinDecimalExponent) | ||
|
||
| { | ||
| while (unsignedSignificand >= ten) | ||
| { | ||
| unsignedSignificand /= ten; | ||
| ++exponent; | ||
| } | ||
| if (exponent < TDecimal.MinDecimalExponent) | ||
| { | ||
| throw new OverflowException(SR.Overflow_Decimal); | ||
| } | ||
| } | ||
|
|
||
| if (unsignedSignificand > TDecimal.MaxSignificand) | ||
| { | ||
| int numberDigitsRemoving = TDecimal.CountDigits(unsignedSignificand) - TDecimal.NumberDigitsPrecision; | ||
|
|
||
| if (exponent + numberDigitsRemoving > TDecimal.MaxDecimalExponent) | ||
stephentoub marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| { | ||
| throw new OverflowException(SR.Overflow_Decimal); | ||
| } | ||
|
|
||
| exponent += numberDigitsRemoving; | ||
| TSignificand two = TSignificand.CreateTruncating(2); | ||
| TSignificand divisor = TDecimal.Power10(numberDigitsRemoving); | ||
| TSignificand quotient = unsignedSignificand / divisor; | ||
| TSignificand remainder = unsignedSignificand % divisor; | ||
RaymondHuy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| TSignificand midPoint = divisor / two; | ||
| bool needRouding = remainder > midPoint || (remainder == midPoint && quotient % two == TSignificand.One); | ||
RaymondHuy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| if (needRouding && quotient == TDecimal.MaxSignificand && exponent < TDecimal.MaxDecimalExponent) | ||
| { | ||
| unsignedSignificand = TDecimal.Power10(TDecimal.NumberDigitsPrecision - 1); | ||
| exponent++; | ||
| } | ||
| else if (needRouding && quotient < TDecimal.MaxSignificand) | ||
| { | ||
| unsignedSignificand = quotient + TSignificand.One; | ||
| } | ||
| else | ||
| { | ||
| unsignedSignificand = quotient; | ||
| } | ||
| } | ||
| else if (exponent > TDecimal.MaxDecimalExponent) | ||
| { | ||
| int numberZeroDigits = exponent - TDecimal.MaxDecimalExponent; | ||
| int numberSignificandDigits = TDecimal.CountDigits(unsignedSignificand); | ||
|
|
||
| if (numberSignificandDigits + numberZeroDigits > TDecimal.NumberDigitsPrecision) | ||
stephentoub marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| { | ||
| throw new OverflowException(SR.Overflow_Decimal); | ||
| } | ||
| unsignedSignificand *= TDecimal.Power10(numberZeroDigits); | ||
| exponent -= numberZeroDigits; | ||
| } | ||
|
|
||
| exponent += TDecimal.Bias; | ||
| bool msbSignificand = (unsignedSignificand & TSignificand.One << TDecimal.MostSignificantBitNumberOfSignificand) != TSignificand.Zero; | ||
|
|
||
| TValue value = TValue.Zero; | ||
| TValue exponentVal = TValue.CreateTruncating(exponent); | ||
| TValue significandVal = TValue.CreateTruncating(unsignedSignificand); | ||
|
|
||
| if (significand < TSignificand.Zero) | ||
| { | ||
| value = TValue.One << TDecimal.NumberBitsEncoding - 1; | ||
| } | ||
|
|
||
| if (msbSignificand) | ||
| { | ||
| value ^= TValue.One << TDecimal.NumberBitsEncoding - 2; | ||
| value ^= TValue.One << TDecimal.NumberBitsEncoding - 3; | ||
| exponentVal <<= TDecimal.NumberBitsEncoding - 4; | ||
| value ^= exponentVal; | ||
| significandVal <<= TDecimal.NumberBitsEncoding - TDecimal.MostSignificantBitNumberOfSignificand; | ||
| significandVal >>= TDecimal.NumberBitsCombinationField; | ||
| value ^= significandVal; | ||
| } | ||
| else | ||
| { | ||
| exponentVal <<= TDecimal.NumberBitsEncoding - TDecimal.NumberBitsExponent - 1; | ||
| value ^= exponentVal; | ||
| value ^= significandVal; | ||
| } | ||
|
|
||
| return value; | ||
| } | ||
|
|
||
| internal struct DecimalIeee754<TSignificand> | ||
| where TSignificand : IBinaryInteger<TSignificand> | ||
| { | ||
| public bool Signed { get; } | ||
| public int Exponent { get; } | ||
| public TSignificand Significand { get; } | ||
|
Comment on lines
131
to
140
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This and other places could likely be a bit more explicit, such as specifying whether this is the biased or unbiased exponent and which part of the significand it is (such as if its already undergone the BID encoding transforms)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, I have updated the struct name and its property names to make it more readable |
||
|
|
||
| public DecimalIeee754(bool signed, int exponent, TSignificand significand) | ||
| { | ||
| Signed = signed; | ||
| Exponent = exponent; | ||
| Significand = significand; | ||
| } | ||
| } | ||
|
|
||
| internal static DecimalIeee754<TSignificand> UnpackDecimalIeee754<TDecimal, TSignificand, TValue>(TValue value) | ||
| where TDecimal : unmanaged, IDecimalIeee754UnpackInfo<TDecimal, TSignificand, TValue> | ||
| where TSignificand : IBinaryInteger<TSignificand> | ||
| where TValue : IBinaryInteger<TValue> | ||
| { | ||
| bool signed = (value & TDecimal.SignMask) != TValue.Zero; | ||
|
||
| TValue g0g1Bits = (value << 1) >> TDecimal.NumberBitsEncoding - 2; | ||
| TSignificand significand; | ||
| int exponent; | ||
|
|
||
| if (g0g1Bits == TValue.CreateTruncating(3)) | ||
| { | ||
| exponent = TDecimal.ConvertToExponent((value << 3) >> TDecimal.NumberBitsEncoding - TDecimal.NumberBitsExponent); | ||
| significand = TDecimal.ConvertToSignificand((value << TDecimal.NumberBitsEncoding + 3) >> TDecimal.NumberBitsEncoding + 3); | ||
| significand += TDecimal.TwoPowerMostSignificantBitNumberOfSignificand; | ||
| } | ||
| else | ||
| { | ||
| exponent = TDecimal.ConvertToExponent((value << 1) >> TDecimal.NumberBitsEncoding - TDecimal.NumberBitsExponent); | ||
| significand = TDecimal.ConvertToSignificand((value << TDecimal.NumberBitsExponent + 1) >> TDecimal.NumberBitsExponent + 1); | ||
| } | ||
|
|
||
| return new DecimalIeee754<TSignificand>(signed, exponent - TDecimal.Bias, significand); | ||
| } | ||
|
|
||
| internal static int CompareDecimalIeee754<TDecimal, TSignificand, TValue>(TValue currentValue, TValue otherValue) | ||
| where TDecimal : unmanaged, IDecimalIeee754UnpackInfo<TDecimal, TSignificand, TValue> | ||
| where TSignificand : IBinaryInteger<TSignificand> | ||
| where TValue : IBinaryInteger<TValue> | ||
| { | ||
| if (currentValue == otherValue) | ||
| { | ||
| return 0; | ||
| } | ||
| DecimalIeee754<TSignificand> current = UnpackDecimalIeee754<TDecimal, TSignificand, TValue>(currentValue); | ||
| DecimalIeee754<TSignificand> other = UnpackDecimalIeee754<TDecimal, TSignificand, TValue>(otherValue); | ||
|
|
||
| if (current.Signed && !other.Signed) return -1; | ||
|
|
||
| if (!current.Signed && other.Signed) return 1; | ||
RaymondHuy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| if (current.Exponent > other.Exponent) | ||
| { | ||
| return current.Signed ? -InternalUnsignedCompare(current, other) : InternalUnsignedCompare(current, other); | ||
RaymondHuy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| if (current.Exponent < other.Exponent) | ||
| { | ||
| return current.Signed ? InternalUnsignedCompare(other, current) : -InternalUnsignedCompare(current, other); | ||
| } | ||
RaymondHuy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| if (current.Significand == other.Significand) return 0; | ||
|
|
||
| if (current.Significand > other.Significand) | ||
| { | ||
| return current.Signed ? -1 : 1; | ||
| } | ||
| else | ||
| { | ||
| return current.Signed ? 1 : -1; | ||
| } | ||
RaymondHuy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| static int InternalUnsignedCompare(DecimalIeee754<TSignificand> biggerExp, DecimalIeee754<TSignificand> smallerExp) | ||
| { | ||
| if (biggerExp.Significand >= smallerExp.Significand) return 1; | ||
|
|
||
| int diffExponent = biggerExp.Exponent - smallerExp.Exponent; | ||
| if (diffExponent < TDecimal.NumberDigitsPrecision) | ||
| { | ||
| TSignificand factor = TDecimal.Power10(diffExponent); | ||
| TSignificand quotient = smallerExp.Significand / biggerExp.Significand; | ||
| TSignificand remainder = smallerExp.Significand % biggerExp.Significand; | ||
|
|
||
| if (quotient < factor) return 1; | ||
| if (quotient > factor) return -1; | ||
| if (remainder > TSignificand.Zero) return -1; | ||
| return 0; | ||
| } | ||
|
|
||
| return 1; | ||
| } | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.