【问题标题】:Is float field + round() for currency fields in django OK?django 中货币字段的浮点字段 + round() 可以吗?
【发布时间】:2014-10-19 03:56:16
【问题描述】:

我在我的 django 项目中使用浮点字段作为货币是天真的。我刚刚了解了 python float 的这个舍入问题:

>>> 0.1 + 0.2 - 0.3
5.551115123125783e-17

现在我有两个选择:

  1. 使用 South 将所有浮点字段迁移到十进制字段,这很痛苦。
  2. 在每次加减运算后执行 round() 以获得正确的结果,然后再保存。毕竟,我的应用程序中的所有货币字段都只允许小数点后一位。

我的问题是,如果我正在处理的只是加减 100.0 和 1.2 之类的数字,那么选项 2 可以吗?除了舍入误差还有什么需要担心的吗?

【问题讨论】:

    标签: python django floating-point decimal


    【解决方案1】:

    小心round(); round(0.1+0.2-0.3+1.2) 会给你 1.0,而不是 1.2。您需要使用Decimal,然后将其正确转换为float:

    >>> r = Decimal('0.1') + Decimal('0.2') - Decimal('0.3')
    >>> r
    Decimal('0.0')
    >>> float(r)
    0.0
    >>> round(0.1+0.2-0.3+1.2)
    1.0
    >>> r = Decimal('0.1') + Decimal('0.2') - Decimal('0.3') + Decimal('1.2')
    >>> r
    Decimal('1.2')
    >>> float(r)
    1.2
    

    这也将处理您必须手动处理的边缘情况,应该使用 float() + round() 方法。

    最后,不要混淆值的打印方式和存储方式。 “只允许 1 个小数位” - 这是一个演示细节。

    【讨论】:

      【解决方案2】:

      使用decimal字段,使用decimal.Decimal,在Python中准确处理货币:

      >>> from decimal import Decimal as D
      >>> D('0.1') + D('0.2') - D('0.3')
      Decimal('0.0')
      >>> assert _ == 0
      

      【讨论】:

        【解决方案3】:

        需要明确的是,问题不在于 Python 的浮点数,而在于浮点数的二进制表示 - 对于易于用十进制表示的数字,它通常并不精确。

        一般来说,我同意您应该使用Decimal 类的其他答案,因为它是为精确表示浮点数而设计的(以空间为代价+数学运算的效率)。另一种选择,如果你确切地知道你的精度是多少(如你所说,一次小数点)将使用整数作为定点数。您将 1.3 存储为 13 并且只知道在显示之前需要将其移动一位小数。但是使用 Decimal 更干净,代码可能更具可读性。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-03-13
          • 2013-07-17
          • 2014-07-10
          • 2013-07-03
          • 2019-03-21
          相关资源
          最近更新 更多