【问题标题】:How to show true numeric value in Python?如何在 Python 中显示真实的数值?
【发布时间】:2020-03-25 19:42:21
【问题描述】:

案例 1

for num in [.1, .2, .3, .4, .5, .6, .7, .8, .9,]:
    print(format(num, ".50f"))
0.10000000000000000555111512312578270211815834045410
0.20000000000000001110223024625156540423631668090820
0.29999999999999998889776975374843459576368331909180
0.40000000000000002220446049250313080847263336181641
0.50000000000000000000000000000000000000000000000000
0.59999999999999997779553950749686919152736663818359
0.69999999999999995559107901499373838305473327636719
0.80000000000000004440892098500626161694526672363281
0.90000000000000002220446049250313080847263336181641

如预期的那样不精确(.5 除外)。


案例 2

for num in [1., 2., 3., 4., 5., 6., 7., 8., 9.]:
    print(format(num, ".50f"))
1.00000000000000000000000000000000000000000000000000
2.00000000000000000000000000000000000000000000000000
3.00000000000000000000000000000000000000000000000000
4.00000000000000000000000000000000000000000000000000
5.00000000000000000000000000000000000000000000000000
6.00000000000000000000000000000000000000000000000000
7.00000000000000000000000000000000000000000000000000
8.00000000000000000000000000000000000000000000000000
9.00000000000000000000000000000000000000000000000000

完美的精度 - ???


众所周知,在计算中不存在完美的浮点整数:所有浮点数都以二进制基数表示,精度随着位大小的增加而增加(float32float64 等)。那么上面的案例 2 是怎么回事呢?即使对于".1000f",零仍然存在,基本上意味着无限精度。此外,0.5 也以某种方式完美呈现。

如果format 不能强制 Python 打印一个浮点数的“真”值,那么什么可以呢?


尝试过的替代方案

  1. format(round(num, 50), ".50f")
  2. format(numpy.float128(num), ".50f")
  3. format(round(numpy.float128(num), 50), ".50f")
  4. format("%.50f" % num)
  5. "{:.50f}".format(num))
  6. f"{num:.50f}"

接受的答案:澄清问题中假设的错误前提;实际问题的答案在问题本身之内 - 使用 format 显示真实数值。

【问题讨论】:

  • 这背后的戈拉是什么?您真的需要显示一个包含 50 个甚至 10 个零的值吗?
  • @azro Yes,有时——但我更感兴趣的是为什么 Python 会在这方面产生误导以及如何规避它
  • 为什么你认为第二组不能用浮点数精确表示?
  • @jonrsharpe 2 的不完全幂 - 基本浮点算术理论;见herehere
  • 我不认为你已经明白这告诉你什么。 3 和 5 可以精确表示,即使它们不是 2 的幂。

标签: python floating-point precision floating-accuracy


【解决方案1】:

整数值实数实际上可以完美精确地用二进制表示。 对于每一个自然数 n,都存在一个自然数 k,以及一个 0-s 和 1-s 的序列,使得:

n = b0*(2^0) + b1*(2^1) + ... + bk*(2^k)

即使您使用浮点类型,这当然也成立。该数字存储在有限位数中,因此具有无限精度。

一些有理数也可以是 - 具体来说,可以表示为:

s = b1*(0.5)^1 + b*2(0.5)^2 + ... + b*k(0.5)^k + n

对于一些自然数 k,n 和一个二进制向量

这就是为什么您可以获得完美的 0.5 精度,而不是其他小数值。例如,尝试 0.75 - 您也可以在这里获得完美的精度。

【讨论】:

  • 没有真正遵循这个解释 - 如果你从 (2^0) 开始,你如何得到 0.5?每个精度级别都应该有一个“原子单位”(即最小的可表示浮点数),以便1.(或.5 的负幂倍数)可以表示为它的 2 的幂 - 你能引用这样的单位吗?
  • 你不是从 2^0 开始的。从 b*(2^0) 开始,b 为 0 或 1。如果 b 为 0,则得到:0*(2^0) = 0。
  • 再一次,你是怎么得到0.5
  • 假设你用 32 位来表示整数部分,在我们的例子中是 0,用 32 位来表示小数部分,在我们的例子中是 1/2。比:0.5 = 0*(2^31) + 0*(2^30) +...+0*(2^0) + 1*(2^(-1)) + 0 * (2^(- 2)) + 0*(2^(-3)) + ..0*(2^(-k))..+ 0*(2^(-32))
  • 那么整数和小数部分是分开表示的吗?不知道 - 在您的答案中包含此内容,最好是对此的引用/参考,然后我会接受它
【解决方案2】:

在常用格式中,如 IEEE 754 64 位二进制浮点数,所有有限浮点数都是二进制小数,形式为 A*2B 的数字,其中 A 和 B 都是有符号整数.

当然,有限格式只能表示二进制分数的有限子集。 A 中的有效位数和 B 的范围都受到格式的限制。对于正常(非次正常)IEEE754 64 位二进制,A 可以有不超过 53 个有效位,并且,对于非零 A 归一化为 1.x 的形式,B 必须在 [−1022, 1023] 范围内.

0.5 可以精确表示,因为它是 1*2-1。 同样,5.0/8.0 (5*2-3) 等数字也是精确的。

在 64 位二进制浮点中,所有适合 32 位二进制的整数都可以精确表示,解释了问题中的第二个表。 9 是 9*20.

对于输出端值得注意的是,每个二进制分数都有一个终止的十进制扩展。这是因为 2 是 10 的因数。打印足够多的数字,您将得到浮点数的确切值。

【讨论】:

  • 感谢您提供高级细节;我现在的问题是,整数部分和小数部分是否按照@NG_ 的建议单独表示?因此,它们会在内存中占用单独的字节/字/等。某种按位图会有所帮助,但不是必需的
  • @OverLordGoldDragon 这确实是一个不同的问题,并且可能是重复的。考虑科学记数法,但在二进制点之前归一化为一位,并且只有分数实际存储。 Double-precision floating-point format 有一个很好的图表。
  • 有副本的链接吗?
猜你喜欢
  • 1970-01-01
  • 2022-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多