Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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']
like image 846
aparpara Avatar asked Mar 25 '19 15:03

aparpara


People also ask

What does NumPy sin return?

The np. sin() NumPy function help to find sine value of the angle in degree and radian. To get sine value of the angle in radians, need to multiply angle with np. pi/180.

Why is sin pi not zero in Python?

Floating point rounding error. Pi cannot be represented exactly as a floating point number, so sin(pi) isn't going to be exactly zero.

Does NumPy sin take radians or degrees?

sin. Trigonometric sine, element-wise. Angle, in radians ( rad equals 360 degrees).

Do Python trig functions accept radians or degrees?

By default all of the trigonometric functions take radians as parameters but we can convert radians to degrees and vice versa as well in NumPy. Note: radians values are pi/180 * degree_values.


1 Answers

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.

Beware Anaconda

like image 75
aparpara Avatar answered Oct 12 '22 15:10

aparpara