关于浮点格式存在一些现有问题,但我认为没有一个回答以下问题。
我正在寻找一种以长、圆润且本地化的格式打印大型浮点数的方法:
>>> print magic_format(1.234e22, locale="en_US")
12,340,000,000,000,000,000,000
>>> print magic_format(1.234e22, locale="fr_FR")
12 340 000 000 000 000 000 000
不幸的是,magic_format
不存在。;-) 我该如何实现它?
细节
这里有几种打印浮点数的方法。它们都没有产生上述输出:
>>> x = 1.234e22
>>> print str(x)
1.234e+22
>>> print repr(x)
1.234e+22
>>> print "%f" % x
12339999999999998951424.000000
>>> print "%g" % x
1.234e+22
失败:要么我得到简短版本,要么得到非分组非本地化非舍入输出。
顺便说一句,我知道 1.234e22 不能完全存储为浮点数,存在必要的舍入误差(这解释了上面的奇数输出)。但是由于str
,repr
并且"%g" % x
能够正确地将其四舍五入到适当的值,我希望有相同的友好四舍五入的数字,但采用长且本地化的形式。
现在让我们尝试本地化...
>>> import locale
>>> locale.setlocale(locale.LC_ALL, "en_US")
'en_US'
>>> locale.format("%g", x, grouping = True)
'1.234e+22'
>>> locale.format("%f", x, grouping = True)
'12,339,999,999,999,998,951,424.000000'
>>> locale.setlocale(locale.LC_ALL, "fr_FR")
'fr_FR'
>>> locale.format("%g", x, grouping = True)
'1,234e+22'
>>> locale.format("%f", x, grouping = True)
'12339999999999998951424,000000'
更近,但不行。我仍然有恼人的舍入错误,而且法语本地化很糟糕,它根本不允许分组。
所以让我们使用优秀的Babel库,也许它可以做我想做的一切:
>>> from babel.numbers import format_number
>>> format_number(x, locale = "en_US")
u'12,339,999,999,999,998,951,424'
>>> format_number(x, locale = "fr_FR")
u'12\xa0339\xa0999\xa0999\xa0999\xa0998\xa0951\xa0424'
哇,真的很近。他们甚至使用牢不可破的空间进行法语分组,我喜欢它。真是太糟糕了,他们仍然有四舍五入的问题。
嘿!?如果我使用python Decimals怎么办?
>>> from decimal import Decimal
>>> Decimal(x)
Decimal('12339999999999998951424')
>>> Decimal("%g" % x)
Decimal('1.234E+22')
>>> "%g" % Decimal("%g" % x)
'1.234e+22'
>>> "%f" % Decimal("%g" % x)
'12339999999999998951424.000000'
没有。我可以得到我想要的数字的精确表示Decimal("%g" % x)
,但是每当我尝试显示它时,它要么很短,要么在打印之前转换为错误的浮点数。
但是如果我将 Babel 和 Decimals 混合在一起呢?
>>> Decimal("%g" % 1.234e22)
Decimal('1.234E+22')
>>> dx = _
>>> format_number(dx, locale = "en_US")
Traceback (most recent call last):
...
TypeError: bad operand type for abs(): 'str'
哎哟。但是 Babel 有一个名为 的函数format_decimal
,让我们用它来代替:
>>> from babel.numbers import format_decimal
>>> format_decimal(dx, locale = "en_US")
Traceback (most recent call last):
...
TypeError: bad operand type for abs(): 'str'
糟糕,format_decimal
无法格式化 python 小数。:-(
好的,最后一个想法:我可以尝试转换为long
.
>>> x = 1.234e22
>>> long(x)
12339999999999998951424L
>>> long(Decimal(x))
12339999999999998951424L
>>> long(Decimal("%g" % x))
12340000000000000000000L
是的!我有我想要格式化的确切数字。让我们把它交给 Babel:
>>> format_number(long(Decimal("%g" % x)), locale = "en_US")
u'12,339,999,999,999,998,951,424'
哦,不......显然Babel在尝试格式化之前将其转换long
为a 。float
我不走运,也没有想法。:-(
如果您认为这很难,请尝试回答相同的问题x = 1.234e-22
。到目前为止,我只能打印简短形式1.234e-22
或0.0
!
我更喜欢这个:
>>> print magic_format(1.234e-22, locale="en_US")
0.0000000000000000000001234
>>> print magic_format(1.234e-22, locale="fr_FR")
0,0000000000000000000001234
>>> print magic_format(1.234e-22, locale="en_US", group_frac=True)
0.000,000,000,000,000,000,000,123,400
>>> print magic_format(1.234e-22, locale="fr_FR", group_frac=True)
0,000 000 000 000 000 000 000 123 400
我可以想象编写一个"1.234e-22"
可以很好地解析和格式化它的小函数,但是我必须了解所有关于数字本地化的规则,而且我宁愿不重新发明轮子,Babel 应该这样做。我应该怎么办?
谢谢你的帮助。:-)