C. Yduqoli
C. Yduqoli

Reputation: 1761

Numpy integer division sometimes yields wrong results when casted

What is the reason those two divisions give different results? I am very confused because with some numbers it gives the same results and with some it doesn't.

>>> import numpy as np
>>> a, b = np.array([844]), np.array([8186])
>>> a.dtype, b.dtype
(dtype('int32'), dtype('int32'))
>>> np.true_divide(a, b, dtype=np.float32)
array([ 0.10310286], dtype=float32)
>>> np.true_divide(a, b, dtype=np.float64)
array([-12.66666667]) # different result
>>> np.true_divide(a, b, dtype=np.float32).astype(np.float64)
array([ 0.10310286])

>>> a, b = np.array([1]), np.array([2])
>>> np.true_divide(a, b, dtype=np.float32)
array([ 0.5], dtype=float32)
>>> np.true_divide(a, b, dtype=np.float64)
array([ 0.5]) # same results

Tested on windows x64, python 3.5 and 3.6 x64, numpy 1.13.1.

EDIT: This was a numpy bug which has since been fixed (https://github.com/numpy/numpy/pull/9469).

Upvotes: 7

Views: 1869

Answers (1)

MB-F
MB-F

Reputation: 23647

This is a bug in numpy. Although this was supposedly fixed in 2015 it looks like it is still causing problems.

When resolving the type signature fails because of the forced cast, true_divide casts the input to int8:

>>> np.int8(844) / np.int8(8186)
-12.666667

>>> np.true_divide(844, 8186, dtype=np.float64)
-12.666666666666666

You get the correct result only for numbers between -128 and 127 because that is the range available in int8.

As a workaround you can specify the complete signature instead of only the return type:

>>> np.true_divide(844, 8186, signature='ii->d')  # int32, int32 -> float64
0.10310285853896897

>>> np.true_divide(844, 8186, signature=(np.int32, np.int32, np.float64))
0.10310285853896897

Upvotes: 1

Related Questions