Python3舍入问题

Python 3 rounding issue

为什么下面的舍入在 python 3 中不起作用,而只在 python 2 中起作用?

random_nums = np.array([-1, 0, 1, 2, 3])
probabilities = np.array([0.01, 0.3, 0.58, 0.1, 0.01])
target = dict(zip(random_nums, probabilities))
target = {k: round(v, 2) for k, v in target.items()}

out:
{-1: 0.01,
 0: 0.29999999999999999,
 1: 0.57999999999999996,
 2: 0.10000000000000001,
 3: 0.01}

似乎工作正常。请记住,round returns 一个浮点数。

它四舍五入到两位小数,但浮点数本质上是不精确的(对于几乎所有数字),因此输出。

您正在使用 NumPy float64 对象而不是 Python float 对象。这会产生一些后果:

  1. 在 Python 3 上,float64 对象使用 NumPy 的舍入代码而不是 Python 进行舍入。 Python 对 float 的舍入代码总是给出正确舍入的结果。 NumPy 的舍入代码没有。 (在 Python 2 上,无法覆盖自定义类型的 round 操作,因此当您在 Python 2 中舍入 float64 对象时,它首先会转换为 Python float,然后 Python 的舍入代码用于给出 float 结果。这是您看到 [=57= 之间差异的主要原因] 2 和 Python 3.)

  2. 再次在 Python 3 上,由于上​​述原因,roundfloat64 上给出了 float64 结果。在 Python 2 上,roundfloat64 对象上给出了 float 结果。

  3. Python float 对象具有不同的 repr,这将提供更令人愉快的输出。特别是,Python 的 float repr 保证了最多 15 位有效数字的十进制值的往返(不是太大,也不是太小):0.58 的表示是 '0.58', 例如。 NumPy float64 对象的表示没有这个 属性:它只是根据存储值的最高 17 位十进制数字打印出结果。

因此,如果您在回合前将您的值转换为 Python float 个对象,您会看到更令人愉快的输出(在某些情况下,结果可能更准确一点)。但请注意,仅仅因为输出看起来不错,并不意味着您得到的结果就是准确的。 None 这改变了 0.58 而不是 可以精确表示为 Python float (或者实际上是 NumPy float64,它使用相同的格式)。请记住,对于二进制浮点数,所见即所得。

Python3 上的一些示例输出:

>>> random_nums = np.array([-1, 0, 1, 2, 3])
>>> probabilities = np.array([0.01, 0.3, 0.58, 0.1, 0.01])
>>> target = dict(zip(random_nums, probabilities))
>>> {k: round(v, 2) for k, v in target.items()}
{0: 0.29999999999999999, 1: 0.57999999999999996, 2: 0.10000000000000001, 3: 0.01, -1: 0.01}
>>> {k: round(float(v), 2) for k, v in target.items()}
{0: 0.3, 1: 0.58, 2: 0.1, 3: 0.01, -1: 0.01}