72

Python Decimal 不支持从 float 构造;它希望您必须先将浮点数转换为字符串。

这是非常不方便的,因为浮点的标准字符串格式化程序要求您指定小数位数而不是有效位数。因此,如果您有一个可能有多达 15 位小数的数字,则需要格式化为,如果您在小数点 ( )Decimal("%.15f" % my_float)之前还有任何有效数字,这将在小数点后 15 位给您带来垃圾。Decimal("%.15f" % 100000.3) == Decimal('100000.300000000002910')

有人可以建议一种在用户输入时从浮点数转换为十进制保留值的好方法,可能会限制可以支持的有效数字的数量吗?

4

11 回答 11

68

蟒蛇 <2.7

"%.15g" % f

或者在 Python 3.0 中:

format(f, ".15g")

Python 2.7+、3.2+

只需将浮点数Decimal直接传递给构造函数,如下所示:

from decimal import Decimal
Decimal(f)
于 2008-11-25T03:07:03.747 回答
29

你在你的问题中说:

有人可以建议一种在用户输入时从浮点转换为十进制保留值的好方法吗

但是每次用户输入一个值时,它都是作为字符串输入的,而不是作为浮点数输入的。您正在某处将其转换为浮点数。直接将其转换为小数,不会丢失任何精度。

于 2008-11-25T03:40:02.620 回答
26

我建议这个

>>> a = 2.111111
>>> a
2.1111110000000002
>>> str(a)
'2.111111'
>>> decimal.Decimal(str(a))
Decimal('2.111111')
于 2011-12-07T10:22:10.207 回答
5

Python 确实支持从浮点数创建十进制。您只需先将其转换为字符串。但是字符串转换不会发生精度损失。您正在转换的浮点数首先没有那种精度。(否则你不需要十进制)

我认为这里的混淆是我们可以创建十进制格式的浮点文字,但是一旦解释器使用该文字,内部表示就会变成浮点数。

于 2008-12-04T22:41:36.170 回答
4

浮点的“官方”字符串表示由内置的 repr() 给出:

>>> repr(1.5)
'1.5'
>>> repr(12345.678901234567890123456789)
'12345.678901234567'

您可以使用 repr() 代替格式化字符串,结果不会包含任何不必要的垃圾。

于 2008-11-25T03:00:30.873 回答
3

您可以通过转换并量化以在逗号后保留 5 位数字

Decimal(float).quantize(Decimal("1.00000"))
于 2021-09-28T12:12:22.627 回答
2

当您说“保留用户输入的值”时,为什么不将用户输入的值存储为字符串,并将其传递给 Decimal 构造函数?

于 2008-11-25T03:44:20.647 回答
2

主要答案有点误导。该g格式忽略小数点后的任何前导零,因此format(0.012345, ".2g")返回 0.012 - 三位小数。如果您需要对小数位数进行硬限制,请使用f格式化程序:format(0.012345, ".2f") == 0.01

于 2020-05-27T14:55:08.017 回答
1

1990 年Steele 和 White 以及 Clinger 的 PLDI 1990论文记录了执行此操作的“正确”方法。

您还可以查看关于 Python Decimal 的SO讨论,包括我建议尝试使用frap 之类的东西来合理化浮点数。

于 2008-11-25T03:41:27.237 回答
1

您可以使用 JSON 来完成它

import json
from decimal import Decimal

float_value = 123456.2365
decimal_value = json.loads(json.dumps(float_value), parse_float=Decimal)
于 2019-12-26T17:07:39.427 回答
0

受此答案的启发,我找到了一种解决方法,该解决方法允许从绕过(仅明显地)字符串步骤的浮点数中缩短 Decimal 的构造:

import decimal
class DecimalBuilder(float):
    def __or__(self, a):
         return decimal.Decimal(str(a))

>>> d = DecimalBuilder()
>>> x = d|0.1
>>> y = d|0.2
>>> x + y # works as desired
Decimal('0.3')
>>> d|0.1 + d|0.2 # does not work as desired, needs parenthesis
TypeError: unsupported operand type(s) for |: 'decimal.Decimal' and 'float'
>>> (d|0.1) + (d|0.2) # works as desired
Decimal('0.3')

这是一种解决方法,但它肯定可以节省代码输入,而且可读性很强。

于 2021-02-17T15:50:43.363 回答