Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/301.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python(奇怪的)舍入值_Python_Numpy_Floating Point - Fatal编程技术网

Python(奇怪的)舍入值

Python(奇怪的)舍入值,python,numpy,floating-point,Python,Numpy,Floating Point,这个问题更多是出于好奇 我正在创建以下数组: A = zeros((2,2)) for i in range(2): A[i,i] = 0.6 A[(i+1)%2,i] = 0.4 print A >>> [[ 0.6 0.4] [ 0.4 0.6]] 然后,打印它: for i,c in enumerate(A): for j,d in enumerate(c): print j, d 但是,如果我去掉j,我得到:

这个问题更多是出于好奇

我正在创建以下数组:

A = zeros((2,2))
for i in range(2):
    A[i,i] = 0.6
    A[(i+1)%2,i] = 0.4
print A

>>>
   [[ 0.6  0.4]
   [ 0.4  0.6]]
然后,打印它:

for i,c in enumerate(A):
    for j,d in enumerate(c):
        print j, d
但是,如果我去掉j,我得到:

>>>
0 0.6
1 0.4
0 0.4
1 0.6
但是如果我从for中删除j,我得到:

(0, 0.59999999999999998)
(1, 0.40000000000000002)
(0, 0.40000000000000002)
(1, 0.59999999999999998)
这是因为我创建矩阵的方式,使用0.6?它如何表示内部真实值?

编辑: 别介意,我没意识到这个问题是关于NumPy的


奇怪的
0.59999999998
和friends是Python准确表示所有计算机如何存储浮点值的最佳尝试:根据IEEE 754标准,它是一组位。值得注意的是,
0.1
是二进制的非终止十进制,因此无法准确存储。(大概是
0.6
0.4

您通常看到
0.6
的原因是大多数浮点打印函数将这些存储不精确的浮点值舍入,以使我们更容易理解。这就是您的第一个打印示例所做的

在某些情况下(即,当打印功能无法让人阅读时),将打印完整的、稍有偏差的编号
0.59999999998
。这就是您的第二个打印示例所做的

tl;博士
这不是Python的错;这只是浮点数的存储方式。

这里发生了一些不同的事情

首先,Python有两种将对象转换为字符串的机制,分别称为
repr
str
repr
应该提供“忠实”的输出,这将(理想情况下)使精确地重新创建该对象变得容易,而
str
的目标是提供更具可读性的输出。对于Python3.1之前(包括Python3.1)的Python版本中的浮点值,
repr
提供足够的数字以完全确定浮点值(以便对返回的字符串求值时准确返回该浮点值),而
str
四舍五入到小数点后12位;这具有隐藏不准确信息的效果,但意味着两个非常接近的不同浮点值可能最终得到相同的
str
值-这是
repr
无法实现的。打印对象时,您将获得该对象的
str
。相反,当您仅在解释器提示下计算表达式时,会得到
repr

例如(这里使用Python 2.7):

但是,从你的角度来看,有点令人困惑,我们得到:

>>> x = 0.4
>>> str(x)
'0.4'
>>> repr(x)
'0.4'
这似乎与您在上面看到的不太吻合,但我们将在下面回到这一点

要记住的第二件事是,在第一个示例中,您正在打印两个单独的项,而在第二个示例中(去掉
j
),您正在打印单个项:长度为2的元组。有些令人惊讶的是,当转换元组以使用
str
打印时,Python仍然使用
repr
来计算该元组元素的字符串表示形式:

>>> x = 1.0 / 7.0
>>> print x, x  # print x twice;  uses str(x)
0.142857142857 0.142857142857
>>> print(x, x)  # print a single tuple; uses repr(x)
(0.14285714285714285, 0.14285714285714285)
这就解释了为什么在这两种情况下会看到不同的结果,即使基本浮动是相同的

但还有最后一块拼图。在Python>=2.7中,我们在上面看到,对于特定的浮点
0.4
,该浮点的
str
repr
是相同的。那么
0.40000000000000002
从何而来?这里没有Python浮点:因为这些值是从NumPy数组中获取的,所以它们实际上是
NumPy.float64

>>> from numpy import zeros
>>> A = zeros((2, 2))
>>> A[:] = [[0.6, 0.4], [0.4, 0.6]]
>>> A
array([[ 0.6,  0.4],
       [ 0.4,  0.6]])
>>> type(A[0, 0])
<type 'numpy.float64'>
因此,这三件事加在一起应该可以解释你看到的结果。请放心,这完全是装饰性的:底层浮点值没有以任何方式更改;对于两种类型:
float
numpy.float64
,通过四种可能的组合
str
repr
显示不同


Python教程给出了Python浮动的存储和显示方式,以及一些潜在的陷阱。答案是关于
str
repr

之间差异的更多信息,但是为什么一个案例打印的是“人性化”版本,而另一个版本打印的是完全精确的?是的,我想是这样的。枚举(A)生成的类型是什么?Tuple也?@default.kramer我不知道这类事情的所有标准。可能是某个C函数的某个参数,几十年来没有人接触过。有关为什么有时表示法比其他表示法更人性化的问题,请参阅马克·迪金森的答案。(请注意,他是唯一有资格回答这个问题的人,因为他是Python的核心开发人员,如果不是对Python最新版本的循环和显示浮动的方式负主要责任的话。)@default.kramer:还要注意,具有大量数字的表示并没有比具有较少数字的表示更精确。由于精确数字在任何有限二进制系统中都不存在,因此长表示和短表示都是实际存储内容的近似值。您可以使用
decimal.decimal
这将完全按照您的预期存储它们。它从2.5或2.6开始就在标准库中(我忘了是哪个了)。等等。“矩阵”?这是标准的Python还是NumPy或其他类似的东西,还是完全其他的东西?@michaelb958:他使用的是NumPy数组,所以显示的值不是Python浮点值;它们是
NumPy.float64
类型的NumPy对象。加上
str
repr
之间的差异,再加上计算元组的
str
使用项目的
repr
,这就解释了这里发生的事情。@larsmans:我同意我们有很多类似的问题,但是,由于马克·迪金森(MarkDickinson)所指出的附加功能,这个特殊的版本有一个转折点。所以在这一次,我没有投票决定结束。我必须改变我的投票,这真的很有启发性
>>> from numpy import zeros
>>> A = zeros((2, 2))
>>> A[:] = [[0.6, 0.4], [0.4, 0.6]]
>>> A
array([[ 0.6,  0.4],
       [ 0.4,  0.6]])
>>> type(A[0, 0])
<type 'numpy.float64'>
>>> from numpy import float64
>>> x = float64(1.0 / 7.0)
>>> str(x)
'0.142857142857'
>>> repr(x)
'0.14285714285714285'
>>> x = float64(0.4)
>>> str(x)
'0.4'
>>> repr(x)
'0.40000000000000002'