Why does numpy.sin return a different result if the argument size is greater than 8192?

筅森魡賤 提交于 2019-11-29 11:59:26

问题


I discovered that numpy.sin behaves differently when the argument size is <= 8192 and when it is > 8192. The difference is in both performance and values returned. Can someone explain this effect?

For example, let's calculate sin(pi/4):

x = np.pi*0.25 for n in range(8191, 8195):     xx = np.repeat(x, n)     %timeit np.sin(xx)     print(n, np.sin(xx)[0]) 
64.7 µs ± 194 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) 8191 0.7071067811865476 64.6 µs ± 166 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) 8192 0.7071067811865476 20.1 µs ± 189 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 8193 0.7071067811865475 21.8 µs ± 13.4 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) 8194 0.7071067811865475 

After crossing the 8192 elements limit the calculations become more than 3 times faster and give a different result: the last digit becomes 5 instead of 6.

When I tried to calculate the same value in other ways I obtained:

  • C++ std::sin (Visual Studio 2017, Win32 platform) gives 0.7071067811865475;
  • C++ std::sin (Visual Studio 2017, x64 platform) gives 0.70710678118654756;
  • math.sin gives 0.7071067811865476, which is logical because I used 64-bit Python.

I couldn't find any explanation in the NumPy documentation, nor in its code.

Update #2: It is hard to believe, but replacing sin by sqrt gives this:

44.2 µs ± 751 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) 8191 0.8862269254527579 44.1 µs ± 543 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) 8192 0.8862269254527579 10.3 µs ± 105 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 8193 0.886226925452758 10.4 µs ± 4.41 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 8194 0.886226925452758 

Update: np.show_config() output:

mkl_info:     libraries = ['mkl_rt']     library_dirs = ['C:/GNU/Anaconda3\\Library\\lib']     define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]     include_dirs = ['C:\\Program Files (x86)\\IntelSWTools\\compilers_and_libraries_2019.0.117\\windows\\mkl', 'C:\\Program Files (x86)\\IntelSWTools\\compilers_and_libraries_2019.0.117\\windows\\mkl\\include', 'C:\\Program Files (x86)\\IntelSWTools\\compilers_and_libraries_2019.0.117\\windows\\mkl\\lib', 'C:/GNU/Anaconda3\\Library\\include'] blas_mkl_info:     libraries = ['mkl_rt']     library_dirs = ['C:/GNU/Anaconda3\\Library\\lib']     define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]     include_dirs = ['C:\\Program Files (x86)\\IntelSWTools\\compilers_and_libraries_2019.0.117\\windows\\mkl', 'C:\\Program Files (x86)\\IntelSWTools\\compilers_and_libraries_2019.0.117\\windows\\mkl\\include', 'C:\\Program Files (x86)\\IntelSWTools\\compilers_and_libraries_2019.0.117\\windows\\mkl\\lib', 'C:/GNU/Anaconda3\\Library\\include'] blas_opt_info:     libraries = ['mkl_rt']     library_dirs = ['C:/GNU/Anaconda3\\Library\\lib']     define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]     include_dirs = ['C:\\Program Files (x86)\\IntelSWTools\\compilers_and_libraries_2019.0.117\\windows\\mkl', 'C:\\Program Files (x86)\\IntelSWTools\\compilers_and_libraries_2019.0.117\\windows\\mkl\\include', 'C:\\Program Files (x86)\\IntelSWTools\\compilers_and_libraries_2019.0.117\\windows\\mkl\\lib', 'C:/GNU/Anaconda3\\Library\\include'] lapack_mkl_info:     libraries = ['mkl_rt']     library_dirs = ['C:/GNU/Anaconda3\\Library\\lib']     define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]     include_dirs = ['C:\\Program Files (x86)\\IntelSWTools\\compilers_and_libraries_2019.0.117\\windows\\mkl', 'C:\\Program Files (x86)\\IntelSWTools\\compilers_and_libraries_2019.0.117\\windows\\mkl\\include', 'C:\\Program Files (x86)\\IntelSWTools\\compilers_and_libraries_2019.0.117\\windows\\mkl\\lib', 'C:/GNU/Anaconda3\\Library\\include'] lapack_opt_info:     libraries = ['mkl_rt']     library_dirs = ['C:/GNU/Anaconda3\\Library\\lib']     define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]     include_dirs = ['C:\\Program Files (x86)\\IntelSWTools\\compilers_and_libraries_2019.0.117\\windows\\mkl', 'C:\\Program Files (x86)\\IntelSWTools\\compilers_and_libraries_2019.0.117\\windows\\mkl\\include', 'C:\\Program Files (x86)\\IntelSWTools\\compilers_and_libraries_2019.0.117\\windows\\mkl\\lib', 'C:/GNU/Anaconda3\\Library\\include'] 

回答1:


As @WarrenWeckesser wrote, "it's almost certainly an Anaconda & Intel MKL issue; cf. https://github.com/numpy/numpy/issues/11448 and https://github.com/ContinuumIO/anaconda-issues/issues/9129".

And unfortunately, the only way to solve the issue under Windows is to uninstall Anaconda and use another distribution with MKL-free numpy. I used python-3.6.6-amd64 from https://www.python.org/ and installed everything else via pip, including numpy 1.14.5. I even managed to make Spyder work (had to downgrade PyQt5 to 5.11.3, it refused to launch on >= 5.12).

Now np.sin(xx) is consistently 0.7071067811865476 (67.1 µs at n = 8192) and np.sqrt(xx) 0.8862269254527579 (16.4 µs). A bit slower, but perfectly reproducible.



来源:https://stackoverflow.com/questions/55341055/why-does-numpy-sin-return-a-different-result-if-the-argument-size-is-greater-tha

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!