Skip to content
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

[API Proposal]: Implement decimal floating-point types that conform to the IEEE 754 standard. #69777

Closed
KTSnowy opened this issue May 25, 2022 · 4 comments
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Numerics
Milestone

Comments

@KTSnowy
Copy link

KTSnowy commented May 25, 2022

Background and motivation

While reading the documentation I noticed that the decimal type implemented in C# and .NET does not conform to the IEEE standard and appears to use it's own format, which can potentially cause issues and limitations in cases where using IEEE conforming decimal floating-point arithmetic are a must (Banks and financial systems).

Extending the current Decimal type with Decimal32, Decimal64 and Decimal128 types as specified in the IEEE standard could make C# and .NET more compatible with banking and financial systems.

It would also make C# one of the few languages that have these decimal types built-in instead of requiring big and complex third-party libraries for decimal floating-point arithmetic.

API Proposal

public readonly struct Decimal128 : 
IComparable, IComparable<decimal128>, 
IConvertible, IEquatable<decimal128>, 
ISpanFormattable, 
System.Runtime.Serialization.IDeserializationCallback, 
System.Runtime.Serialization.ISerializable;

API Usage

/// <summary>
/// Keeping my fortune in Decimals to avoid the round-off errors.
/// Example adapted from .net documentation.
/// </summary>
class PiggyBank {
    // Type can be decimal (original), decimal32, decimal64 or decimal128 (IEEE standard)
    protected decimal128 MyFortune;

    public void AddPenny() {
        MyFortune = Decimal.Add(MyFortune, .01m);
    }

    public decimal Capacity {
        get {
            return Decimal.MaxValue;
        }
    }

    public decimal Dollars {
        get {
            return Decimal.Floor(MyFortune);
        }
    }

    public decimal Cents {
        get {
            return Decimal.Subtract(MyFortune, Decimal.Floor(MyFortune));
        }
    }

    public override string ToString() {
        return MyFortune.ToString("C")+" in piggy bank";
    }
}

Alternative Designs

Alternatively, instead of providing new decimal types, change the current implementation to conform to the IEEE standard. This is a risky alternative though as it could potentially break backwards compatibility of apps that rely on the old implemention.

Risks

There shouldn't be any risks of adding new alternative decimal types (decimal32, decimal64 amd decimal128) since the original type will be unchanged and use of them would be "opt-in" by manually changing source code to use the new types.

Changing the current implementation of the decimal type instead would most likely be risky as there could be a number of different apps relying on that particular implementation.

@KTSnowy KTSnowy added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label May 25, 2022
@ghost ghost added the untriaged New issue has not been triaged by the area owner label May 25, 2022
@ghost
Copy link

ghost commented May 25, 2022

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

Issue Details

Background and motivation

While reading the documentation I noticed that the decimal type implemented in C# and .NET does not conform to the IEEE standard and appears to use it's own format, which can potentially cause issues and limitations in cases where using IEEE conforming decimal floating-point arithmetic are a must (Banks and financial systems).

Extending the current Decimal type with Decimal32, Decimal64 and Decimal128 types as specified in the IEEE standard could make C# and .NET more compatible with banking and financial systems.

It would also make C# one of the few languages that have these decimal types built-in instead of requiring big and complex third-party libraries for decimal floating-point arithmetic.

API Proposal

public readonly struct Decimal128 : 
IComparable, IComparable<decimal128>, 
IConvertible, IEquatable<decimal128>, 
ISpanFormattable, 
System.Runtime.Serialization.IDeserializationCallback, 
System.Runtime.Serialization.ISerializable;

API Usage

/// <summary>
/// Keeping my fortune in Decimals to avoid the round-off errors.
/// Example adapted from .net documentation.
/// </summary>
class PiggyBank {
    // Type can be decimal (original), decimal32, decimal64 or decimal128 (IEEE standard)
    protected decimal128 MyFortune;

    public void AddPenny() {
        MyFortune = Decimal.Add(MyFortune, .01m);
    }

    public decimal Capacity {
        get {
            return Decimal.MaxValue;
        }
    }

    public decimal Dollars {
        get {
            return Decimal.Floor(MyFortune);
        }
    }

    public decimal Cents {
        get {
            return Decimal.Subtract(MyFortune, Decimal.Floor(MyFortune));
        }
    }

    public override string ToString() {
        return MyFortune.ToString("C")+" in piggy bank";
    }
}

Alternative Designs

Alternatively, instead of providing new decimal types, change the current implementation to conform to the IEEE standard. This is a risky alternative though as it could potentially break backwards compatibility of apps that rely on the old implemention.

Risks

There shouldn't be any risks of adding new alternative decimal types (decimal32, decimal64 amd decimal128) since the original type will be unchanged and use of them would be "opt-in" by manually changing source code to use the new types.

Changing the current implementation of the decimal type instead would most likely be risky as there could be a number of different apps relying on that particular implementation.

Author: KTSnowy
Assignees: -
Labels:

api-suggestion, area-System.Numerics, untriaged

Milestone: -

@huoyaoyuan
Copy link
Member

If we implement this, we'd probably implement Decimal32 Decimal64 together.

The implemented interfaces would be a hybrid of newly introduced Int128, Half, and existing Decimal:

public readonly struct Decimal128:
IFloatingPointIeee754<Decimal128>, ISignedNumber<Decimal128>, IMinMaxValue<Decimal128>

@tannergooding
Copy link
Member

I generally have a desire to expose these types both to solve some common user-requests around things System.Decimal is "lacking", but also to provide more performance oriented APIs, and to ensure we implement a well-defined standard for such types.

It's worth noting that C vNext currently plans on exposing _Decimal32, _Decimal64, and _Decimal128 and so getting these in will allow better interop on that level.

public readonly struct Decimal128 :
IComparable, IComparable,
IConvertible, IEquatable,
ISpanFormattable,
System.Runtime.Serialization.IDeserializationCallback,
System.Runtime.Serialization.ISerializable;

Some feedback:

  • This should not include System.IConvertible, System.Runtime.Serialization.ISerializable, or System.Runtime.Serialization.IDeserializationCallback.
  • This can be simplified down to IDecimalFloatingPointIeee754<Decimal128> and IMinMaxValue<Decimal128>
    • The former (IDecimalFloatingPointIeee754<Decimal128>) includes System.IComparable, System.IComparable<Decimal128>, System.IEquatable<Decimal128>, and System.ISpanFormattable.
  • This should be expanded to include Decimal32 and Decimal64
  • All three of these types should likely be under System.Numerics to avoid conflicts or potential confusion related to System.Decimal
  • These declarations need to be as fleshed out as possible, including conversions

The IDecimalFloatingPointIeee754<TSelf> declaration should be included. This is minimally described in https://github.com/dotnet/designs/tree/main/accepted/2021/statics-in-interfaces:

public interface IDecimalFloatingPointIeee754<TSelf>
        : IFloatingPointIeee754<TSelf>
        where TSelf : IDecimalFloatingPointIeee754<TSelf>
    {
        // This interface is defined for convenience of viewing the IEEE requirements
        // it would not actually be defined until the .NET libraries requires it

        // 5.3.2
        //  TSelf Quantize(TSelf x, TSelf y);
        //  TSelf Quantum(TSelf x);

        // 5.5.2
        //  TDecEnc EncodeDecimal(TSelf x);
        //  TSelf DecodeDecimal(TDecEnc x);
        //  TBinEnc EncodeBinary(TSelf x);
        //  TSelf DecodeBinary(TBinEnc x);

        // 5.7.3
        //  bool SameQuantum(TSelf x, TSelf y);
    }

All of the described APIs unique to that interface likely need a bit more thought

  • Quantize is like CopySign but for the Quantum. But it may result in a NaN in some cases
  • Quantum returns the number represented by -1^0 * 10^q * s. That is, it effectively returns the actual exponent
  • EncodeDecimal, DecodeDecimal, EncodeBinary, and DecodeBinary allow taking a Decimal32/64/128 type and forcing whether it is stored in the binary or decimal encoding (the former is a raw mantissa and the latter is n declets).

@tannergooding tannergooding added this to the Future milestone Jul 15, 2022
@tannergooding tannergooding added needs-further-triage Issue has been initially triaged, but needs deeper consideration or reconsideration and removed untriaged New issue has not been triaged by the area owner labels Jul 15, 2022
@dakersnar
Copy link
Contributor

Closing this as a duplicate of the above. Thank you for the proposal @KTSnowy!

@ghost ghost locked as resolved and limited conversation to collaborators Mar 2, 2023
@tannergooding tannergooding removed the needs-further-triage Issue has been initially triaged, but needs deeper consideration or reconsideration label Jun 24, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Numerics
Projects
None yet
Development

No branches or pull requests

4 participants