【问题标题】:Inaccuracy of decimal in .NET.NET 中的小数点不准确
【发布时间】:2015-11-18 19:23:41
【问题描述】:

昨天在调试过程中我发生了一件奇怪的事情,我无法解释:

所以也许我在这里没有看到明显的东西,或者我误解了 .NET 中的小数点,但结果不应该是一样的吗?

【问题讨论】:

标签: c# .net decimal floating-accuracy


【解决方案1】:

decimal 不是一个神奇的为我做所有的数学类型。它仍然是一个浮点数 - 与float 的主要区别在于它是一个十进制 浮点数,而不是二进制。所以你可以很容易地将0.3 表示为十进制(不可能作为有限的二进制数),但你没有无限的精度。

这使它更接近于人类进行相同的计算,但您仍然必须想象有人单独执行每个操作。它专为财务计算而设计,您无需像在数学中那样做 - 您只需一步一步地根据非常具体的规则对每个结果进行四舍五入。

事实上,在很多情况下,decimal 的效果可能比float 差很多(或者更好,double)。这是因为decimal 根本不进行任何自动舍入。对double 执行相同操作会得到预期的 22,因为它自动假定差异无关紧要 - 在 decimal 中,它确实 - 这是关于 decimal 的重点之一.当然,您可以通过插入手动 Math.Rounds 来模拟这一点,但这没有多大意义。

【讨论】:

    【解决方案2】:

    Decimal 只能在其精度限制内准确存储可以用十进制精确表示的值。这里 22/24 = 0.91666666666666666666666... 需要无限精度有理类型来存储,四舍五入后不再等于 22/24。

    如果你先做乘法,那么所有的值都是可以精确表示的,因此你会看到结果。

    【讨论】:

      【解决方案3】:

      通过添加括号,您可以确保在乘法之前计算除法。这看起来足以影响计算,足以引入floating precision issue

      由于计算机实际上无法生成所有可能的数字,因此您应该确保将其纳入计算中

      【讨论】:

      • 作为一个小提示,人类实际上也不能产生所有可能的数字。 1 / 3 就是一个很好的例子,因为每个人都会决定什么精度对他们来说是足够的,并且永远不会试图弄清楚是否有解决方案。 (剧透:没有。它总是递归的 3)
      • 人类可以做的很酷的事情是,在剩下的计算中将其保留为1 / 3,或者写为0.33(无限扩展)。即使是无理数,我们也可以写出它们是如何定义的,或者只使用一个常数。当您对精度非常认真时非常方便:D
      • @Luaan 或者在计算的那个点切换到三进制,写0.1。 :)
      • @Luaan:计算机也可以做很酷的事情。只是当您告诉他们使用有限精度浮点数进行计算时,他们会服从。
      • 人类和计算机都知道1/3 是浮点基数3 中的0.1
      【解决方案4】:

      虽然DecimalDouble 具有更高的精度,但它的主要有用特性是每个值精确匹配其人类可读的表示。虽然在某些语言中可用的固定十进制类型可以保证两个匹配精度的定点值的加法或减法,或者定点类型乘以一个整数,都不会导致舍入错误,而“大十进制”类型(例如 Java 中的类型)可以保证乘法不会导致舍入错误,浮点 Decimal 类型(例如 .NET 中的类型)不提供此类保证,并且没有十进制类型可以保证除法运算可以在没有舍入错误的情况下完成(如果需要舍入,Java 可以选择抛出异常)。

      虽然那些决定将Decimal 设为浮点类型的人可能打算将其用于需要在小数点右侧或左侧更多位的情况下,但浮点类型,无论是基数-10 或以 2 为底,使所有运算都不可避免地出现舍入问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-07-09
        • 2015-09-07
        • 2011-01-07
        • 2011-02-19
        • 1970-01-01
        • 2017-06-08
        相关资源
        最近更新 更多