【问题标题】:What data type should I use to represent money in C#?我应该使用什么数据类型来表示 C# 中的钱?
【发布时间】:2023-03-04 07:42:07
【问题描述】:

在 C# 中,我应该使用什么数据类型来表示货币金额?十进制?漂浮?双倍的?我要考虑:精度、舍入等。

【问题讨论】:

    标签: c#


    【解决方案1】:

    使用System.Decimal:

    Decimal 值类型表示 十进制数,范围从正数 79,228,162,514,264,337,593,543,950,335 为负 79,228,162,514,264,337,593,543,950,335。 Decimal 值类型是合适的 对于需要的财务计算 大量显着积分 和小数位数,没有四舍五入 错误。 Decimal 类型不 消除四舍五入的需要。 相反,它可以最大限度地减少错误,因为 四舍五入。

    System.Single (float)System.Double (double)足够精确能够表示高精度浮点数而不会出现舍入误差。

    【讨论】:

    • 我对此表示赞成,但我对最终的主张提出异议。并不是浮点数/双精度数不够精确 - 只是他们使用了不合适的货币基础。您可以有一个 512 位浮点二进制值,其实际 精度 比十进制高 - 但它仍然不合适,因为它不能准确表示十进制值,例如 0.1。
    • 我还是不同意你的最后一句话。我会说:“任何依赖二进制尾数的浮点系统都无法将所有十进制百分位表示为有理数。
    • Nosredna,您在这里遇到了问题,因为我认为您对“非理性”的含义有误解。非理性对于基数的选择是不变的;一个确切的真实值要么是不合理的,要么不是。基数的选择无关紧要。您实际上想要在这里做出的区分与理性无关,而是与表示错误有关。
    • 埃里克,说得好。 1/10 可以用固定位数的十进制表示,但不能用二进制表示。在二进制中,它是一个重复的分数。
    • 您应该说的是,任何带有二进制尾数的有限浮点系统都无法精确表示所有十进制的百分之一。也就是说,不会产生表示错误。更多关于浮点运算中表示错误的基本问题分析,你可能想看我写的关于这个主题的系列文章:blogs.msdn.com/ericlippert/archive/tags/…
    【解决方案2】:

    如果您使用 SQL,请在数据库中使用小数和货币。

    【讨论】:

      【解决方案3】:

      Decimal 是你想要的。

      【讨论】:

        【解决方案4】:

        在 C# 中,Decimal 类型实际上是一个结构体,其中包含所有以 10 为底的数学和比较操作的重载函数,因此它的舍入误差较小。另一方面,浮点数(和双精度数)类似于二进制的科学记数法。因此,当您知道所需的精度时,十进制类型会更准确。

        运行这个来看看2的准确率差异:

        using System;
        using System.Collections.Generic;
        using System.Text;
        
        namespace FloatVsDecimal
        {
            class Program
            {
                static void Main(string[] args) 
                {
                    Decimal _decimal = 1.0m;
                    float _float = 1.0f;
                    for (int _i = 0; _i < 5; _i++)
                    {
                        Console.WriteLine("float: {0}, decimal: {1}", 
                                        _float.ToString("e10"), 
                                        _decimal.ToString("e10"));
                        _decimal += 0.1m;
                        _float += 0.1f;
                    }
                    Console.ReadKey();
                }
            }
        }
        

        【讨论】:

          【解决方案5】:

          考虑使用Money Type for the CLR。它是一种自定义值类型(结构),还支持货币并处理四舍五入问题。

          【讨论】:

          • 我正在阅读“通过 C# 的自适应代码”一书(自 2014 年起),它说:“不建议使用小数类型来表示货币值(...)。取而代之的是金钱( url 与上面相同)值类型。我很困惑,因为我一直被告知使用小数。作者没有争论为什么我们不应该使用小数。基于此和乔治写的,我猜十进制是要走的路。
          • @Marshall 我猜是因为decimal 不包含任何关于我们正在处理的货币的信息。美元?欧元?还有什么?
          【解决方案6】:

          在 C# 中,您应该使用“Decimal”来表示货币金额。

          【讨论】:

            【解决方案7】:

            对于快速而肮脏的事情,任何浮点基本类型都可以。

            floatdouble 的问题在于它们都不能准确地表示 1/10,有时会导致惊人的万亿分之一美分。您可能听说过臭名昭著的 10¢ + 20¢。更实际地,尝试计算三件商品的 6% 销售税,每件税前价值为 39.99 美元。

            此外,floatdouble 具有负无穷大和 NaN 之类的值,它们对于表示金钱毫无用处。所以decimal,可以精确代表1/10似乎是最好的选择。

            但是,decimal 没有任何关于我们正在处理的货币的信息。例如,29.89 美元的金额是否等于 29.89 欧元? 29.89 美元 > 29.89 欧元?如何确保这些金额以正确的货币符号显示?

            如果这些细节对您的程序很重要,那么您应该使用第三方库或创建自己的 CurrencyAmount 类(或任何您想要的名称)。

            但如果这类事情对程序来说无关紧要,你可以只使用浮点类型。或者甚至可能是整数(例如,我在 Java 中的二十一点实现要求玩家输入整数的赌注)。

            【讨论】:

              猜你喜欢
              • 2011-10-19
              • 1970-01-01
              • 2011-04-28
              • 1970-01-01
              • 2021-01-05
              • 2023-04-02
              • 2010-12-23
              • 2011-09-21
              • 1970-01-01
              相关资源
              最近更新 更多