1

I saw a very strange behavior in numpy array, when I mixed int32 and int8 arrays in a simple operation, the int32 array element ct[4,0] seems to have become 8bit when taking the result of += dleng[4]*4:

import numpy as np
In[3]: ct = np.zeros((6,1), np.int32)
In[4]: ct
Out[4]: 
array([[0],
   [0],
   [0],
   [0],
   [0],
   [0]], dtype=int32)
In[5]: dleng = np.zeros((6, 1), np.int8)
In[6]: dleng[0] = 2
dleng[1] = 3
dleng[2] = 4
dleng[3] = 7
dleng[4] = 3
dleng[5] = 5
In[7]: dleng
Out[7]: 
array([[2],
   [3],
   [4],
   [7],
   [3],
   [5]], dtype=int8)
In[8]: ct[4] = 117
In[9]: ct
Out[9]: 
array([[  0],
   [  0],
   [  0],
   [  0],
   [117],
   [  0]], dtype=int32)
In[10]: ct[4,0] += dleng[4]*4
In[11]: ct
Out[11]: 
array([[   0],
   [   0],
   [   0],
   [   0],
   [-127],
   [   0]], dtype=int32)}

Does anyone know why this might happen?

2 Answers 2

1

dleng[4]*4 is an array:

In [94]: dleng[4]
Out[94]: array([3], dtype=int8)

In [95]: dleng[4]*4
Out[95]: array([12], dtype=int8)

while ct[4, 0] is a scalar with type np.int32:

In [98]: ct[4,0]
Out[98]: 117

In [99]: type(_)
Out[99]: numpy.int32

As @WallyBeaver points out, ct[4,0] += dleng[4]*4 is like ct[4,0] = ct[4,0] + dleng[4]*4. That last expression is a scalar plus an array. In that situation, the data type is determined by the array, so it ends up being np.int8. There is a note about this in the numpy docs:

Mixed scalar-array operations use a different set of casting rules that ensure that a scalar cannot “upcast” an array unless the scalar is of a fundamentally different kind of data (i.e., under a different hierarchy in the data-type hierarchy) than the array. This rule enables you to use scalar constants in your code (which, as Python types, are interpreted accordingly in ufuncs) without worrying about whether the precision of the scalar constant will cause upcasting on your large (small precision) array.

A fix is to write the in-place addition as

ct[4,0] += dleng[4,0]*4
Sign up to request clarification or add additional context in comments.

1 Comment

Ok this makes sense. Definitely something to pay attention to in the future!
1

It's because what you are doing is:

>>> ct[4,0] += dleng[4]*4

Which is actually this:

>>> ct[4,0] = ct[4,0] + dleng[4]*4

Which produces this:

>>> ct[4,0] + dleng[4]*4
array([-127], dtype=int8)

Which then does this:

>>> ct[4,0] = array([-127], dtype=int8)

But is really doing this type conversion under the covers:

>>> a.astype(np.int32)
array([-127], dtype=int32)

3 Comments

I don't understand why ct[4,0] + dleng[4]*4 produces array([-127], dtype=int8) --- why is it cast to int8 instead of int32?
Ah I understand now after seeing both yours and Warren's answers.
Yeah, ct[4,0] is 117, which is then cast to an int8 upon addition.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.