【问题标题】:Convert to Float without Rounding Decimal Places转换为浮点数而不舍入小数位
【发布时间】:2012-12-04 03:37:40
【问题描述】:

我有一个列表,其中包含某个数字'5.74536541',我将其转换为浮点数。

我在 Python 3 中使用("%0.2f" % (variable)) 将其打印出来,但它总是打印出 5.75 而不是 5.74。

我知道您在考虑谁在乎,但它是针对货币转换器程序的,我不希望货币向上/向下舍入,而是要准确。

我怎样才能让它不四舍五入,但同时保留 2 位小数?

【问题讨论】:

  • 如果你确定字符串是一个数字,那么你可以直接处理文本。
  • 你的问题没有意义,5.75 比 5.74 更接近数字。将数字存储为浮点数,并让它们四舍五入打印 - 有什么问题?
  • @wim:他没有在问题中提到原因吗? I know you're thinking who cares, but it is for a currency converter program and I don't want the currencies to round up/down but to be exact.
  • 但这并不“准确”。正确的做法是让所有的数学都完全精确(甚至可能使用十进制模块,用于财务方面),并且仅出于打印目的而舍入。

标签: python list floating-point


【解决方案1】:

由于您提到的舍入错误,您不应该使用浮点数作为货币。

最好的办法是使用fixed-precision decimal,您还可以完全控制舍入和截断的工作方式。来自文档:

>>> from decimal import *
>>> getcontext()
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999,
    capitals=1, flags=[], traps=[Overflow, DivisionByZero,
    InvalidOperation])

>>> getcontext().prec = 6
>>> Decimal('3.0')
Decimal('3.0')
>>> Decimal('3.1415926535')
Decimal('3.1415926535')
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85987')
>>> getcontext().rounding = ROUND_UP
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85988')

您应该在内部以高精度将所有基于货币的值表示为 Decimals(在您的情况下,标准精度水平应该没问题 - 只需保留 prec !)。如果您想向用户打印格式良好的美元和美分值,使用locale 模块是一种直接的方法。

打印时要小心,因为您必须将Decimal 量化到正确的显示位数,否则舍入将不会基于您的Decimal 上下文!您应该只为最终显示或单个最终值执行 quantize 步骤 - 所有中间步骤都应使用高精度 Decimals 以使任何操作尽可能准确。

>>> from decimal import *
>>> import locale
>>> locale.setlocale(locale.LC_ALL, '')
'en_AU.UTF-8'
>>> getcontext().rounding = ROUND_DOWN
>>> TWOPLACES = Decimal(10) ** -2
>>> var = Decimal('5.74536541')
Decimal('5.74536541')
>>> var.quantize(TWOPLACES)
Decimal('5.74')
>>> locale.currency(var.quantize(TWOPLACES))
'$5.74'

【讨论】:

  • 我正在做 getcontext().prec = 2,然后 var = Decimal('5.74536541') 但它只打印出 5.74536541?
  • 当您创建一个新的Decimal 对象时,它会以表示该对象所需的精度创建(参见上面的示例,其中在设置上下文后输入的 Pi 具有 6 个以上的有效数字) .对该十进制进行操作应该返回一个具有上下文精度的新十进制对象(例如var - 0)。你确定要这么低的精度吗?我想您可能希望保持所需的精度和ROUND_DOWN 以获得最终的两位数显示?此外,对于您的示例, prec = 2 应该产生 5.7
  • 这很奇怪,文档说 >>> getcontext().prec = 6 >>> Decimal(1) / Decimal(7) 返回 >>> Decimal('0.142857'),但我试过了那对我不起作用。 prec = 2 是否意味着它保留 2 个小数位,还是我在想别的东西?不幸的是,是的,我需要保留 2 位小数,因为 5.74 美元存在,但 5.745 美元不是真正的货币价值。
  • 新小数的重要性仅由输入的位数决定。上下文精度和舍入仅在算术运算期间发挥作用。请注意,精度控制有效数字,不一定是小数位。尝试一些更大的数字来测试一下!
  • 总而言之,您应该使用Decimal 对象并以高精度进行所有计算。要打印美元和美分值,请考虑使用locale。我会用一个例子来更新我的答案。
【解决方案2】:

如果您处理货币和准确性问题,请不要使用float,使用decimal

【讨论】:

    【解决方案3】:

    去掉数字 mod 0.01

    rounded = number - (number % 0.01)
    

    然后像以前一样打印出来。

    也就是说,向下取整更准确。您是否正在尝试利用舍入错误方案从银行窃取资金?

    【讨论】:

    • This said, rounding down is not more accurate. 但是,当您兑换货币时,银行不会给您更多。这是截断的正当理由。
    • 即使来自$2,000.00,它也会占用0.01,这是错误的。
    【解决方案4】:

    浮点值被称为“有用的近似值”。无论您对浮点数做什么(舍入、截断等),如果结果是浮点值,就无法决定小数点右边的位数它有。

    永远不要对货币使用浮点值。例如,请参阅pydoc decimal。 Python的十进制模块支持十进制定点和十进制浮点运算。

    Python 文档warn about rounding floats.

    注意对于浮点数的 round() 行为可能令人惊讶:对于 例如,round(2.675, 2) 给出 2.67 而不是预期的 2.68。这个 不是错误:这是因为大多数小数 不能完全表示为浮点数。

    如果你不小心,你会是misled by the value that appears at the interpreter prompt

    Python 只打印真实十进制值的十进制近似值 机器存储的二进制近似值。

    重要的是要意识到这实际上是一种幻觉: 机器中的值不完全是 1/10,你只是四舍五入 机器真值的显示。这一事实变得显而易见 当您尝试使用这些值进行算术运算时

    【讨论】:

      【解决方案5】:

      如果数字是字符串,则将字符串截断为小数点后仅 2 个字符,然后将其转换为浮点数。 否则将其乘以 10^n,其中 n 是小数点后的位数,然后将浮点数除以 10^n。

      【讨论】:

        猜你喜欢
        • 2021-10-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-04-10
        • 1970-01-01
        • 1970-01-01
        • 2015-12-19
        • 1970-01-01
        相关资源
        最近更新 更多