5

In this case, why does x += y produce a different result than x = x + y?

import numpy as np

x = np.repeat([1], 10)
y = np.random.random(len(x))

x += y
print x
# Output: [1 1 1 1 1 1 1 1 1 1]

x = x + y
print x
# Output: [ 1.50859536  1.31434732  1.15147365  1.76979431  1.64727364
#           1.02372535  1.39335253  1.71878847  1.48823703  1.99458116]
jamylak
  • 128,818
  • 30
  • 231
  • 230
user805627
  • 4,247
  • 6
  • 32
  • 43

2 Answers2

9

Although the linked question explains the general issue, there is a numpy-specific explanation for this particular case. Basically, those answers say "it depends on the type of the variables involved", and what I'm giving below is the explanation for numpy types.

When you do x + y, numpy uses a "lowest common denominator" datatype for the result. Since x is int and y is float, this means it returns a float array.

But when you do x += y, you are forcing it to conform to the dtype of x, which is int. This truncates the decimal portion and leaves all x values back at 1. This is the way numpy defines the augmented assignment operators: it forces the return value to be of the same dtype as the assignment target.

You can get the first behavior from the second example by doing x = (x + y).astype(int) (explicitly forcing the dtype back to int). You can get the second behavior from the first example by letting x = np.repeat([1.0], 10) (using a float makes x have dtype float, so now you can add y to it without truncation).

BrenBarn
  • 242,874
  • 37
  • 412
  • 384
2

This is due to the difference between __add__ and __iadd__ methods

However usually the difference is seen between mutable vs immutable objects

>>> x = np.repeat([1], 10)
>>> y = np.random.random(len(x))
>>> x += y
>>> x
array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1])

contrast with

>>> x = np.repeat([1.0], 10)
>>> x += y
>>> x
array([ 1.05192255,  1.00844068,  1.27569982,  1.40997015,  1.17270114,
        1.27335121,  1.70719855,  1.72778867,  1.64679031,  1.23241938])

so __iadd__ is causing the addition to be truncated back to int when x is int type

This makes sense if you think about it - x can't magically change the type of it's elements (where would it store those extra bytes)

for __add__ there is no problem producting a new array of floats instead of ints

John La Rooy
  • 295,403
  • 53
  • 369
  • 502