Numpy: BUG:np.min并不总是传播NaN

创建于 2018-01-11  ·  65评论  ·  资料来源: numpy/numpy

这项调查是由于scipy CI在最近几天(即1.14发布后)开始在传送带

在我的家用计算机上(macOS,conda python 3.6.2,conda numpy):

>>> import numpy as np
>>> np.version.version
'1.14.0'
>>> np.min([1.0, 2.0, np.nan])
nan
>>> np.min([1.0, np.nan, 2.0])
nan
>>> np.min([np.nan, 1.0, 2.0])
nan
>>> np.min([np.nan, 1.0])
/Users/andrew/miniconda3/envs/dev3/lib/python3.6/site-packages/numpy/core/_methods.py:29: RuntimeWarning: invalid value encountered in reduce
  return umr_minimum(a, axis, None, out, keepdims)
nan

在我的工作计算机上(macOS,conda python 3.6.2,在干净的环境中通过pip安装的numpy):

>>> import numpy as np
>>> np.version.version
'1.14.0'
>>> np.min([1., 2., 3., 4., np.nan])
nan
>>> np.min([1., 2., 3., np.nan, 4.])
nan
>>> np.min([1., 2., np.nan, 3., 4.])
nan
>>> np.min([1., np.nan, 2., 3., 4.])
nan
>>> np.min([np.nan, 1., 2., 3., 4.])
nan
>>> np.min([np.nan, 1.])
nan
>>> np.min([np.nan, 1., np.nan])
nan
>>> np.min([1., np.nan])
nan
>>> np.seterr(all='raise')
{'divide': 'warn', 'over': 'warn', 'under': 'ignore', 'invalid': 'warn'}
>>> np.min([1., np.nan])
nan
>>> np.min([np.nan, 1.])
nan
>>> np.min([np.nan, 1., 2., 3., 4.])
nan
>>> np.min([np.nan, 1., 2., 3., 4.])
nan

对于第一组代码示例,为什么前三个示例不产生警告,而仅导致最后一个警告?
在第二组示例中,根本没有发出警告。

00 - Bug numpy.core

所有65条评论

外部参照scipy / scipy#8282,scipy / scipy#8279

我认为这里的另一点是,可能是不同的代码路径触发了不同的行为(我认为不是真正的numpy),例如,由于使用了AVX等,我想我有时看到矢量东西无法设置错误cpu标志,并且因为如果不使用它们,可能会显得有些随机。

Dunno如果这与它有很大关系,但是我希望它,numpy通常不会对浮点错误做太多事情。 除了检查是否发生任何事情。

而且正如Chuck所说,不幸的是,在不同的系统上,许多浮点错误标志是不同的。

好的,了解为什么错误仅在某些安装中发生而在其他安装中不发生。
scipy在可能包含NaN的数组上使用np.min的原因是,这是检查它们是否存在的快速方法。 numpy文档建议这样做是允许的:

将传播NaN值,即,如果至少一项是NaN,则相应的最小值也将是NaN。

鉴于这是np.min允许的使用案例之一,从使用角度来看,我完全不希望发出任何警告/错误。

(显然,还有其他方法可以实现这一点,例如np.isnan(arr).any() ,但这不会改变我上面的推理)

我猜这根本不是一个合理的变化。

+1完全没有警告

你好

我偶然发现了类似的不一致之处:

>>> import numpy
>>> import warnings
>>> warnings.simplefilter("always", category=RuntimeWarning)
>>> numpy.min(numpy.full((7,), numpy.nan, dtype=numpy.float64))
nan
>>> numpy.min(numpy.full((8,), numpy.nan, dtype=numpy.float64))
/home/user/env/lib/python3.6/site-packages/numpy/core/_methods.py:29: RuntimeWarning: invalid value encountered in reduce
  return umr_minimum(a, axis, None, out, keepdims)
nan

为什么形状大于8会引发RuntimeWarning?

@NotSqrt @seberg当输入数组的大小变为8时,min根本无法正确传播NaN时,我看到了类似的行为:

> cat np-min-wat.py
import numpy as np

print "numpy version:", np.__version__
print ""

def show_min(input):
    print ""
    arr = np.array(input)
    print arr.dtype, arr
    print "this should be nan as per docs:", arr.min()
    arr = np.array

input = [31., 487., np.nan, 10000., 10000., 19., 101., 22., 1000., 300., 10.]
for x in xrange(3, len(input) + 1):
    show_min(input[0:x])

在OSX和Windows上显示这种相当奇怪的行为,但在Linux上则没有。使用python 2.7.13和numpy 1.14.2的fresh virtualenv:

numpy version: 1.14.2

/Users/kip/ac/Environments/test/lib/python2.7/site-packages/numpy/core/_methods.py:29: RuntimeWarning: invalid value encountered in reduce
  return umr_minimum(a, axis, None, out, keepdims)

float64 [ 31. 487.  nan]
this should be nan as per docs: nan

float64 [   31.   487.    nan 10000.]
this should be nan as per docs: nan

float64 [   31.   487.    nan 10000. 10000.]
this should be nan as per docs: nan

float64 [   31.   487.    nan 10000. 10000.    19.]
this should be nan as per docs: nan

float64 [   31.   487.    nan 10000. 10000.    19.   101.]
this should be nan as per docs: nan

float64 [   31.   487.    nan 10000. 10000.    19.   101.    22.]
this should be nan as per docs: 19.0

float64 [   31.   487.    nan 10000. 10000.    19.   101.    22.  1000.]
this should be nan as per docs: 19.0

float64 [   31.   487.    nan 10000. 10000.    19.   101.    22.  1000.   300.]
this should be nan as per docs: nan

float64 [   31.   487.    nan 10000. 10000.    19.   101.    22.  1000.   300.
    10.]
this should be nan as per docs: nan

看到两个“这应该是docs的nan: 19.0 ”行吗?

同样,在numpy 1.13.1上没有出现警告(这是我第一次观察到此行为的地方。)

@kippr您从哪里获得NumPy的?

我猜这八个元素的边界可能与AVX512有关,问题是编译器和CPU的某种组合。 您在哪个cpus / compiler上看到问题?

@juliantaylor有想法吗?

对齐也可能会产生影响。

@charris

感谢您看我的帖子..回答您的问题:

中央处理器
❃sysctl -n machdep.cpu.brand_string Intel(R)Core(TM)i7-6700K CPU @ 4.00GHz

NumPy是通过pip在我的Mac上以全新的virtualenv安装的(通过自制软件安装的python 2.7.13),所以我猜它使用了所有默认的编译器标记等?

我刚刚重新创建了虚拟环境并重新运行了pip安装,这看起来与我有关,但是安装时会出现很多消息。(附加完整日志。)请让我知道是否还有其他信息可以从构建目录或其他目录中退出,或者可以尝试使用编译标志。

[..]
 Downloading numpy-1.14.2.zip (4.9MB):                                                                                                                                                                                                                                            
  Downloading from URL https://pypi.python.org/packages/0b/66/86185402ee2d55865c675c06a5cfef742e39f4635a4ce1b1aefd20711c13/numpy-1.14.2.zip#md5=080f01a19707cf467393e426382c7619 (from https://pypi.python.org/simple/numpy/)                                                      
...Downloading numpy-1.14.2.zip (4.9MB): 4.9MB downloaded              
[..]
    building library "npymath" sources
    get_default_fcompiler: matching types: '['gnu95', 'nag', 'absoft', 'ibm', 'intel', 'gnu', 'g95', 'pg']'
    customize Gnu95FCompiler
    Found executable /usr/local/bin/gfortran
    customize Gnu95FCompiler
    customize Gnu95FCompiler using config
    C compiler: clang -fno-strict-aliasing -fno-common -dynamic -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/System/Library/Frameworks/Tk.framework/Versions/8.5/Headers -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes

    compile options: '-Inumpy/core/src/private -Inumpy/core/src -Inumpy/core -Inumpy/core/src/npymath -Inumpy/core/src/multiarray -Inumpy/core/src/umath -Inumpy/core/src/npysort -I/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/include/python2.7 -c'
    clang: _configtest.c
    clang _configtest.o -o _configtest
    success!
    removing: _configtest.c _configtest.o _configtest

谢谢
克里斯

build.log

ps可能不足为奇,但是max出现相同的行为:

numpy version: 1.14.2


arr.dtype, arr: float64 [ 31. 487.  nan]
/Users/kip/ac/Environments/meh/lib/python2.7/site-packages/numpy/core/_methods.py:29: RuntimeWarning: invalid value encountered in reduce
  return umr_minimum(a, axis, None, out, keepdims)
arr.min(): nan
/Users/kip/ac/Environments/meh/lib/python2.7/site-packages/numpy/core/_methods.py:26: RuntimeWarning: invalid value encountered in reduce
  return umr_maximum(a, axis, None, out, keepdims)
arr.max(): nan
np.amin(arr): nan
np.nanmin(arr): 31.0

arr.dtype, arr: float64 [   31.   487.    nan 10000.]
arr.min(): nan
arr.max(): nan
np.amin(arr): nan
np.nanmin(arr): 31.0

arr.dtype, arr: float64 [   31.   487.    nan 10000. 10000.]
arr.min(): nan
arr.max(): nan
np.amin(arr): nan
np.nanmin(arr): 31.0

arr.dtype, arr: float64 [   31.   487.    nan 10000. 10000.    19.]
arr.min(): nan
arr.max(): nan
np.amin(arr): nan
np.nanmin(arr): 19.0

arr.dtype, arr: float64 [   31.   487.    nan 10000. 10000.    19.   101.]
arr.min(): nan
arr.max(): nan
np.amin(arr): nan
np.nanmin(arr): 19.0

arr.dtype, arr: float64 [   31.   487.    nan 10000. 10000.    19.   101.    22.]
arr.min(): 19.0
arr.max(): 10000.0
np.amin(arr): 19.0
np.nanmin(arr): 19.0

arr.dtype, arr: float64 [   31.   487.    nan 10000. 10000.    19.   101.    22.  1000.]
arr.min(): 19.0
arr.max(): 10000.0
np.amin(arr): 19.0
np.nanmin(arr): 19.0

arr.dtype, arr: float64 [   31.   487.    nan 10000. 10000.    19.   101.    22.  1000.   300.]
arr.min(): nan
arr.max(): nan
np.amin(arr): nan
np.nanmin(arr): 19.0

arr.dtype, arr: float64 [   31.   487.    nan 10000. 10000.    19.   101.    22.  1000.   300.
    10.]
arr.min(): nan
arr.max(): nan
np.amin(arr): nan
np.nanmin(arr): 10.0

我使用的CPU具有相同的numpy版本(在arch上),该版本也具有AVX2和sse4.2功能,但在Linux上看不到它。 也许与mac / clang有关?

编辑/修订:(我尝试过挑衅一些对齐方式,没有检查警告部分,但是我看不到错误的结果部分)

我猜有一个cpu标志设置不正确,可能与编译器有关。

如果只是为了跟踪它,我们应该进行测试以证明这个问题。 @kippr是什么

np.min(np.diagflat([np.nan]*10), axis=0)

在您的安装上做什么?

@charris

看起来还可以:

In [1]: import numpy as np

In [2]: np.min(np.diagflat([np.nan]*10), axis=0)
Out[2]: array([ nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan])

但是我尝试了一些连击,发现了以下内容(请参阅最后一个,8个值和axis = 1):

In [3]: np.min(np.diagflat([np.nan]*10), axis=1)
Out[3]: array([ nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan])

In [4]: np.min(np.diagflat([np.nan]*8), axis=0)
Out[4]: array([ nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan])

In [5]: np.min(np.diagflat([np.nan]*8), axis=1)
Out[5]: array([ nan,  nan,   0.,   0.,  nan,   0.,  nan,  nan])

相当神秘..不确定是否完全有助于了解原因。

@seberg-是的,是的,我在Mac和Windows上都观察到了这种现象,但是linux很好。

谢谢
克里斯

@kippr这是一个非常令人不安的错误,因为它会影响基本操作,而该问题似乎并非源自NumPy。 我们可以尝试在MAC和Windows上关闭矢量化功能,看看是否有帮助。 您仅在Python 2.7上看到此问题吗?

我在NumPy中看不到任何会更改此行为1.14的内容。 也许OpenBLAS摆弄了控件...

@juliantaylor @VictorRodriguez有什么想法吗?

@charris

我在Mac上的python 3中也看到了此行为:

Python 3.6.0 (default, Jan 23 2017, 20:09:28)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np

>>> np.min(np.diagflat([np.nan]*8), axis=1)
array([nan, nan,  0.,  0., nan,  0., nan, nan])
>>> np.__version__
'1.14.2'

Nb我首先在Mac上的python 2.7下的NumPy版本1.13中注意到了此行为,因此它不是1.14中引入的回归:

Python 2.7.10 (default, Feb  7 2017, 00:08:15)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.34)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np
>>> np.min(np.diagflat([np.nan]*8), axis=1)
array([ nan,  nan,   0.,   0.,  nan,   0.,  nan,  nan])
>>> np.__version__
'1.13.1'

并在cygwin / Windows中复制它:

$ python
Python 2.7.13 (default, Mar 13 2017, 20:56:15)
[GCC 5.4.0] on cygwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np
>>> np.min(np.diagflat([np.nan]*8), axis=1)
array([ nan,  nan,   0.,   0.,  nan,   0.,  nan,  nan])
>>> np.__version__
'1.13.1'

但是在Linux中看不到这个问题:

Python 2.7.6 (default, Oct 26 2016, 20:32:47) 
[GCC 4.8.4] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np
>>> np.min(np.diagflat([np.nan]*8), axis=1)
array([ nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan])
>>> np.__version__
'1.13.1'

@charris我在进行numpy性能优化的过程中看到过,openblas和编译器标志会影响numpy / scipy的行为(根据我的经验)。 我们可以采取的第一步是将其附加到C(使用openblas库)测试中,以便我们可以隔离行为并查看它是否可以复制。 还要仔细检查,这只是在MAC和Windows上对吗? 我在Linux上看不到这种现象(在avx补丁进入1.15版本之前,所以它们不会影响这个行为)。 @kippr您是如何在Mac / Windows中构建numpy的? 问候

嗨@VictorRodriguez

这是通过在两个平台上的pip安装来完成的,在Mac机壳中是一个全新的virtualenv。 参见上文,我在其中为pip粘贴了日志,其中包括python 2.7安装的编译输出。 (Python 3 pip安装似乎很麻烦。)

干杯克里斯

嗨伙计
我可以提供更多帮助的信息吗?

谢谢

在Mac(可能还有其他平台)上,由于编译器(在Mac上默认为clang / llvm而不是gcc)正在以一种有问题的方式重新排序SSE2命令,因此发生了该错误。 中的错误:

np.min(np.diagflat([np.nan]*8), axis=1)

之所以发生,是因为正在运行的代码是从以下位置生成的sse2_minimum_DOUBLE:
https://github.com/numpy/numpy/blob/d7d5cb3feccc1fc6cf57159e8b9fe0a733968706/numpy/core/src/umath/simd.inc.src#L1020

具体来说,让我们看一下第1041行中函数内的这段代码(我已经自动扩展了SSE2表单):

        }
        c1 = _mm_min_pd(c1, c2);

        if (npy_get_floatstatus() & NPY_FPE_INVALID) {
            *op = NPY_NAN;
        }
        else {
            npy_double tmp = sse2_horizontal_min___m128d(c1);
            ....
         }

编译器不了解c1分配和npy_get_floatstatus()是相关的,因此将代码更改为:

        }
        if (npy_get_floatstatus() & NPY_FPE_INVALID) {
            *op = NPY_NAN;
        }
        else {
            c1 = _mm_min_pd(c1, c2);
            npy_double tmp = sse2_horizontal_min___m128d(c1);
            ....
         }

这当然是胡说八道...我不知道什么是建议的方法,以使其在优化下不这样做。 (我认为其他平台对此有STDC FENV_ACCESS编译指示吗?)

也许由于此代码的更改已使用5年了,所以该错误是由新版本的clang和其他优化引起的吗?

谢谢@tzickel

自从许多个月前的高中毕业以来,我还没有写过C,所以我绝对不会想出解决这个问题的聪明方法,但是我确实尝试了一些方法来迫使编译器按照原始顺序进行评估:将上述if语句更改为:

if ((sizeof(c1) != 0) || (sizeof(c1) == 0) & npy_get_floatstatus() & NPY_FPE_INVALID) {

确实,一旦执行此操作,该错误就会消失。

(我还尝试了其他一些较简单的形式,以使编译器在if语句之前评估_mm_min_pd,例如,通过在if语句的两边以及在if / else块之后放置对c1的引用,全部无济于事。我怀疑它要么重新排序了,但总是运行c = _mm_min_pd分配,或者认为我的电话实际上是某种形式的noop。

但是无论如何,我都可以确认您已经确定了我所看到的错误,希望有人可以有一个很好的方法来提示编译器,使_mm_min_pd和npy_get_floatstatus的顺序保持不变。

好的,谷歌建议的另一件事也可以起作用:将c1标记为volatile:

https://github.com/numpy/numpy/blob/d7d5cb3feccc1fc6cf57159e8b9fe0a733968706/numpy/core/src/umath/simd.inc.src#L1029

变成:

        /* load the first elements */
        @vtype@ volatile c1 = @vpre@_load_@vsuf@((@type@*)&ip[i]);
        @vtype@ c2 = @vpre@_load_@vsuf@((@type@*)&ip[i + stride]);
        i += 2 * stride;

但是我不确定这是否是实现目标的最佳方法。

非常感谢对此@tzickel进行的额外调试,这是非常深入的调试, @kippr我有一个问题,您提到这是在Mac上全新安装的pip,因此不应该从头开始构建吗? 另外,如果我使用gcc在Linux系统上运行:

$蟒蛇
Python 3.6.5(默认,2018年4月1日,15:40:54)
Linux上的[GCC 7.3.0]
键入“帮助”,“版权”,“信用”或“许可证”以获取更多信息。

将numpy导入为np
np.version.version
'1.14.2'
np.min([1。,2.,3.,4.,np.nan])

np.min([1。,2.,3.,np.nan,4.])

np.min([1。,2.,np.nan,3.,4.])

np.min([1。,np.nan,2.,3.,4.])

np.min([np.nan,1.,2.,3.,4.])

np.min([np.nan,1.])

np.min([np.nan,1.,np.nan])

np.min([1。,np.nan])

np.seterr(all ='raise')
{'divide':'warn','over':'warn','under':'ignore','invalid':'warn'}
np.min([np.nan,1.0])

并且根本看不到任何警告,因此也许如前所述,c铛可能是问题所在。 唯一让我感到奇怪的是,为什么您通过pip install numpy看到了这一点。 它是如何建造的? 以及使用了哪些标志?

我的mac也没有错误:

https://hastebin.com/cuzinajero.swift

我想知道是否可以通过以下方式使它更安全

if (c1 = n_mm_min_pd(c1, c2), py_get_floatstatus() & NPY_FPE_INVALID) {

@juliantaylor有想法吗?

甚至

return_nan = (c1 = n_mm_min_pd(c1, c2), py_get_floatstatus() & NPY_FPE_INVALID);
if (return_nan) {

尽管可能不是线程安全的,但逗号运算符应该是一个序列点。 嗯,我想知道simd代码中多少

@VictorRodriguez如果我使用python2.7在我的Mac上运行pip install numpy,它将从源代码构建。 如果我使用python3运行pip install,它将通过轮子安装。

我捕获了pip安装的完整输出: https :

为了测试上面的更改,我从源代码(当前的主服务器)构建,但是检查了一下,我仍然没有发现损坏的行为。 构建时,我使用了INSTALL.rst.txt中建议的命令行:
python setup.py build -j 4 install --prefix $HOME/.local

请注意,这里有人说他也已经在Windows中看到该bug。 我认为它不是在Windows上用clang编译的,而是MSVC或GCC编译的,这可能意味着numpy不遵守平台规则。 在Windows中,numpy使用_statusfp获取fp状态,MSDN文档指出:

许多数学库函数会修改浮点状态字,结果无法预测。 优化可以对_status87,_statusfp和相关函数的调用进行重新排序,合并和消除浮点运算。 使用/ Od(禁用(调试))编译器选项或fenv_access pragma指令可防止优化对浮点运算进行重新排序。

GCC和MSVC(但现在还不是clang)具有实用性来控制它。

@tzickel确信Windows版本表示它与cygwin有关。 MSVC不会为我复制它。

总的来说,我喜欢@charris的建议,它是标准C,不需要编译指示,并且AFAICT不会增加任何开销

/* use the comma operator to prevent optimization changing the order of evaluation */
if (c1 = n_mm_min_pd(c1, c2), py_get_floatstatus() & NPY_FPE_INVALID) {

即使用于python 2.7的visual studio 8编译器也支持
第二个更紧凑的建议似乎太模糊了

代码中是否还有其他地方容易受到此错误的影响?

  1. cygwin版本表示GCC,这意味着该错误应像linux一样起作用?

  2. 如果我正确理解,则逗号运算符不会帮助您进行优化,它可以在代码生成的另一个层次上工作。 编译器仍然可以自由地认为这两个表达式无关,并且可以随意移动它们。 这是一个小例子,说明是这种情况(尝试使用其旁边的行更改注释代码),检查与调用外部函数有关的minpd(确保在编译器标志中给出了-O3),然后在GCC和CLANG(似乎GCC主干目前具有相同的错误:)):

https://godbolt.org/g/Zoc5xr

  1. 如果您查看fenv.h,则访问该文件的代码中的每个函数基本上都具有相同的潜在问题。 因此,在numpy / core / src / npymath / ieee754.c中使用的代码中正在调用的所有内容

  2. 我认为,clang当前无法通过优化为此类函数生成安全的代码,因此选项为:
    A.用gcc编译(至少使用官方的mac wheel),如果用clang编译,则产生警告。
    B. Clang支持每个函数的optnone属性,如果使用clang编译,则可以将其撒在此类函数上以禁用所有优化(慢速但正确的代码):
    https://clang.llvm.org/docs/AttributeReference.html#optnone -clang-optnone-clang-optnone

切换到逗号运算符根本没有帮助- ;已经是一个序列点。

@ eric-wieser您确定吗? 我没有看到;被列为序列点。 https://msdn.microsoft.com/zh-CN/library/azk8zbxd.aspx

在任何情况下,都保证逗号运算符的参数的求值顺序是保证的,而用;分隔的语句则不是这种情况。

@charris不幸的是,建议的更改似乎无法解决问题:

diff --git a/numpy/core/src/umath/simd.inc.src b/numpy/core/src/umath/simd.inc.src
index 2241414ac..8345e3ef7 100644
--- a/numpy/core/src/umath/simd.inc.src
+++ b/numpy/core/src/umath/simd.inc.src
@@ -1038,9 +1038,8 @@ sse2_@kind@_@TYPE@(@type@ * ip, @type@ * op, const npy_intp n)
             c1 = @vpre@_@VOP@_@vsuf@(c1, v1);
             c2 = @vpre@_@VOP@_@vsuf@(c2, v2);
         }
-        c1 = @vpre@_@VOP@_@vsuf@(c1, c2);

-        if (npy_get_floatstatus() & NPY_FPE_INVALID) {
+        if (c1 = @vpre@_@VOP@_@vsuf@(c1, c2), npy_get_floatstatus() & NPY_FPE_INVALID) {
             *op = @nan@;
         }
         else {

注意,将变量标记为volatile确实可以解决该问题。

如果您想尝试其他变体,请告诉我。

似乎编译器没有遵守有关逗号运算符的规范,至少在我们了解规范的情况下。 对于编译器当前状态,最简单的解决方案似乎是添加volatile ,尽管它看起来很脆弱。

好吧,GCC 8.1刚刚发布,您猜怎么着...具有优化功能的GCC现在产生的问题与clang在此处的相同问题https://github.com/numpy/numpy/issues/10370#issuecomment -384154230可以按预期提供帮助,但volatile可以提供帮助),尽管我不知道distutils是否在gcc标志中启用了缓解这种情况的功能,但我认为不会。

这是GCC 8.1上的代码(可以与7.3进行比较):
https://godbolt.org/g/AJRdRQ

在asm中搜索minpd和npy_get_floatstatus调用。

暂时让我们与volatile一起进行一些测试,这些测试有望在出现问题时发出信号。 我们可能会看到的另一种选择是一个单独的函数,可以在其中使用volatile或编译器指令,但将其放在一个位置以使其易于管理。

比这个特定问题要大得多。 调用ieee754.c中的函数的所有numpy代码都必须进行审核和修复。 (也许再次重命名此问题,或者更好的是,打开一个新问题)。

minpd指令的令人惊讶的行为可能与https://github.com/numpy/numpy/issues/10370#issuecomment -381241813有关:

如果该指令的NaN(SNaN或QNaN)只有一个值,则将第二个操作数(源操作数),即NaN或有效的浮点值写入结果中。

参见: http :

@mattkretz似乎并非如此。 (这是预期的行为,以及为何已进行此检查的原因)。

@tzickel出于好奇,问题出现在哪个优化级别? 我们曾经将自己限制为-O2 ,但是我认为某些平台一直在使用-O3或同等水平。

类似于此gcc错误,我认为: https :

似乎在这里设置#pragma STDC FENV_ACCESS ON是正确的解决方案,但是它确实需要C99,我们需要删除python 2.7才能使用。 也许GCC --std=c90模式假设它可以进行优化,因为缺少实用性

对于您所有的问题,只需转到此处的链接:

https://godbolt.org/g/AJRdRQ(*它似乎是共享的,因此可以将输入内容复制到新窗口中)

并尝试更改编译器版本,编译器标志和代码,并即时查看结果...

在两个最新的编译器上甚至使用-O1时,都会发生这种情况。 #pragma似乎没有任何作用。

该版本非常复杂,汇编程序太多,很难将汇编程序与c代码关联。 原始版本要简单得多,并且可以解决该问题。

另见公关

嗯...。有人可以告诉我在哪个OS /编译器上编译了numpy-1.14.3-cp27-cp27mu-manylinux1_x86_64.whl(来自pypi档案)吗? 我认为这里也可能存在另一个(相关)问题。

@tzickel我相信默认的ubuntu可信编译器是gcc 4.8,我看不到已安装了最新的东西。

@charris manylinux容器在安装了gcc 4.2的情况下运行Centos5。

@ngoldbaum感谢您的信息。 我们将需要尽快为Python 3.7构建轮子。 就像在travis.yml构建矩阵中添加MB_PYTHON_VERSION=3.7条目一样容易吗?

我认为您需要等到manylinux工具得到更新。 在python3.6发布IIRC之后花了几周的时间。 @njsmith可能知道更多。

@ngoldbaum是什么促使gcc 4.2 ? 如果我们愿意,使用更高版本的编译器是否容易?

是什么推动了gcc 4.2的选择?

我相信目标是启用足够老的glibc进行编译,以使二进制兼容性问题在实践中不会成为问题

如果我们愿意,使用更高版本的编译器是否容易?

我不知道。 我也不知道numpy如何管理建筑轮子。 我正在为我的项目使用Matthew Brett的multibuild项目,我需要等到更新后为我的项目构建python3.7轮子。

好的,不确定这是否是最终的相关问题,但是我想我在该SSE代码中发现了另一个问题:

在numpy 1.14.0中,添加了一些代码,以在出现FP错误时抛出运行时警告:
https://github.com/numpy/numpy/commit/d47ca7b26172c42b01c3132d0e46e70578c8ea21

但是,如果我们再次查看SSE实施:
https://github.com/numpy/numpy/blob/d7d5cb3feccc1fc6cf57159e8b9fe0a733968706/numpy/core/src/umath/simd.inc.src#L1020

我们可以看到,它仅通过阵列的中间对齐部分通过了FPU,而头和尾(它们不是SSEable,因为它们不是内存对齐的)是手动检查的,而不是通过FPU,而SSE部分会触发,因此只有中间部分会触发NaN警告,而另一部分(在输入和输出相等时)不会触发。 那样行吗 ?

np.min([1,np.nan,1,1,1,1,1,1])不会触发运行时警告
但是np.min([1,1,np.nan,1,1,1,1,1])可以。

np.min([1,np.nan,1,1,1,1,1,1])不会触发运行时警告

@tzickel这与#11029有关,对吗?

编辑:格式化

似乎问题出在#8954,导致PR#9020

是的,但我的意思是,#9020并未涵盖所有可能的情况。 其中之一就是该SSE代码(它颠覆了该机制以进行一些优化)。

至于#11029,我想弄清楚为什么在这里和那里的帖子中,除了NaN传播错误外,有时还会显示警告,有时却不显示

另一个问题是,如果输入中同时存在NaN是min / max两者的结果,并且我们已经检查了isNan / valid,那么在发现NaN的第一个实例时是否应该快速退出?

@tzickel还原操作均未提前退出。 如果将来将它们重构为gufuncs,它们可能会出现。

此页面是否有帮助?
0 / 5 - 0 等级