当前位置: 首页 > 知识库问答 >
问题:

将float转换为位置格式的字符串(没有科学符号和假精度)

公良安邦
2023-03-14

我想打印一些浮点数,使它们始终以十进制形式书写(例如12345000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,而不是科学符号,但我希望结果具有IEEE 754双倍的最多约15.7个有效数字,而不是更多。

理想的情况是,结果是位置十进制格式的最短字符串,当转换为float时,仍然得到相同的值。

众所周知,如果指数大于15或小于-4,则floatrepr是以科学符号写成的:

>>> n = 0.000000054321654321
>>> n
5.4321654321e-08  # scientific notation

如果使用str,则生成的字符串仍然是科学符号:

>>> str(n)
'5.4321654321e-08'

有人建议,我可以使用带有f标志和足够精度的format来摆脱科学符号:

>>> format(0.00000005, '.20f')
'0.00000005000000000000'

它适用于这个数字,尽管它有一些额外的尾随零。但.1的相同格式将失败,它给出的十进制数字超出了float的实际机器精度:

>>> format(0.1, '.20f')
'0.10000000000000000555'

如果我的号码是4.5678e-20,使用.20f仍然会失去相对精度:

>>> format(4.5678e-20, '.20f')
'0.00000000000000000005'

这就引出了一个问题:以十进制格式打印任意浮点数的最简单且性能良好的方法是什么,它与repr(n)(或Python 3上的str(n))中的数字相同,但始终使用十进制格式,而不是科学符号。

即,将浮点值0.00000005转换为字符串'0.00000005'的函数或操作;0.1'0.1'4200000000000000000000转换为'42000000000000000000000000'420000000000000000并将浮点值-4.5678E-5格式化为'-0.000045678'

赏金期之后:看来至少有两种可行的方法,正如Karin所演示的,使用字符串操作可以实现比我在Python2上的初始算法显著的速度提升。

因此,

  • 如果性能很重要并且需要Python2兼容性;或者由于某种原因不能使用decimal模块,那么Karin使用字符串操作的方法就是实现方法。
  • 在Python 3上,我的代码稍微短一些也会更快。

共有1个答案

轩辕晔
2023-03-14

不幸的是,似乎连带有float.__format__的新式格式都不支持这一点。floats的默认格式与repr相同;使用f标志时,默认情况下有6个小数位数:

>>> format(0.0000000005, 'f')
'0.000000'

然而,有一种方法可以获得所需的结果--不是最快的结果,而是相对简单的结果:

  • 首先使用str()repr()
  • 将浮点转换为字符串
  • 然后根据该字符串创建一个新的decimal实例。
  • decimal.__format__支持f标志,该标志提供所需的结果,并且与float不同,它打印实际精度而不是默认精度。

因此,我们可以创建一个简单的实用函数float_to_str:

import decimal

# create a new context for this task
ctx = decimal.Context()

# 20 digits should be enough for everyone :D
ctx.prec = 20

def float_to_str(f):
    """
    Convert the given float to a string,
    without resorting to scientific notation
    """
    d1 = ctx.create_decimal(repr(f))
    return format(d1, 'f')

必须注意不要使用全局十进制上下文,因此为该函数构造了一个新的上下文。这是最快的方式;另一种方法是使用decimal.local_context,但速度会慢一些,为每次转换创建一个新的线程本地上下文和一个上下文管理器。

该函数现在返回从尾数起包含所有可能数字的字符串,四舍五入到最短的等效表示:

>>> float_to_str(0.1)
'0.1'
>>> float_to_str(0.00000005)
'0.00000005'
>>> float_to_str(420000000000000000.0)
'420000000000000000'
>>> float_to_str(0.000000000123123123123123123123)
'0.00000000012312312312312313'

最后一个结果在最后一位四舍五入

正如@karin所指出的,float_to_str(42000000000000000000000.0)并不严格符合预期的格式;它返回4200000000000000,而不拖尾.0

 类似资料:
  • 问题内容: 我想打印一些浮点数,以使它们始终以十进制形式写(例如或,而不是科学计数法,但是我希望结果具有IEEE 754倍数的最多〜15.7的有效数字,仅此而已。 理想情况下 , __ 我想要 的结果是 位置十进制格式 的 最短 字符串,当转换为a时仍会得到相同的值 。 众所周知,如果指数大于15或小于-4,则用科学记数法写a的: 如果使用,则结果字符串再次采用科学计数法: 有人建议我可以用用标志

  • 很多问题都解决了这个问题,但没有一个解决方案能完全满足我的需要。 我有一个数据框,有两列数字,每列10-20位。这些实际上是ID,我想将它们连接起来。看起来最好先将值转换为字符串。 然而,当使用转换时,熊猫保留了科学符号,这是不会飞的。 我尝试过的事情: 尝试:dtype arg('str')或转换器(使用)在 结果:

  • 在我的例子中,其中一个xml标记值是"09031454866678e6"。而在中转换为json对象e被认为是科学符号,并转换为“9.031454866678E6”。 我应该如何避免这种转换并确保它被解析为字符串而不是数字? 在代码中: 其中resp是xml字符串。 设置值时失败 setobject方法如下所示 项目中使用的maven依赖项是 我期望输出与原始值“09031454866678e6”相

  • 问题内容: 我想要这种格式 问题答案: 您需要先 解析 日期字符串(使用方法),才能 使用与格式匹配的格式获取对象。 然后使用所需的格式来 格式化 Date对象(Use 方法)以获取字符串。 输出:- 第一种格式是RFC 822 TimeZone与您的日期字符串匹配。有关在日期格式中使用的其他各种选项,请参见。

  • 问题内容: 如何使用PEM格式的字符串创建实例?PEM格式的字符串是HTTP请求“ SSL_CLIENT_CERT”标头值。 答案 : 根据mgaert的回答,这是我在Scala中写的内容 : 问题答案: 将Base64解码为二进制,并用一些InputStream读取它,然后尝试

  • 如何将日期字段从科学符号转换为freemarker中的数字,然后根据该日期字段的值进行sort_by? 如果我能从Freemarker文档注释中获得一些指针或任何特定的参考,我将很高兴。