19

I'm having some strange behavior in my python code related to - and -=. I'm writing a QR decomposition using numpy, and have the following line of code in a double loop:

v = v - r[i,j] * q[:,i]

where q and r are both numpy.array, and v is a slice of another numpy.array taken as v = x[:,j].

The above code doesn't work as expected in all cases. However, if I make the following change:

v -= r[i,j] * q[:,i]

Then everything works flawlessly.

I was under the impression that those two lines should be identical. To test whether -= and _ = _ - were working differently, I created the following snippet

import numpy

x = numpy.array(range(0,6))
y = numpy.array(range(0,6))

u = x[3:5]
v = y[3:5]

print u,v

u = u - [1,1]
v -= [1,1]

print u,v

which again works as expected, producing [2 3] [2 3] at both print statements.

So I'm entirely confused why those two lines perform differently. The only possible thing I can think of is that I am dealing with extremely small numbers sometimes (on the order of 10^-8 or smaller) and there is some precision issue that -= is better at? The first line performs increasingly worse as the elements of x get smaller.

I apologize if there's any other posts about this similar issue, I can't search for - and -= and I don't know if there's any correct terms for these besides assignment/operators.

Thanks for any help!

juliomalegria
  • 24,229
  • 14
  • 73
  • 89
Josh
  • 1,248
  • 12
  • 25
  • 4
    For future reference if you want to search for stuff like this the names for `-` and `-=` are [`__sub__`][1] and [`__isub__`][2] respectively. So: `a = a - b` is equivalent to `a = a.__sub__(b)` `a -= b` is equivalent to `a.__isub__(b)`. (unless __isub__ is undefined, then it falls back on the above) [1]: http://pyref.infogami.com/__add__ [2]: http://pyref.infogami.com/__iadd__ – Free Monica Cellio Jan 28 '12 at 17:31

3 Answers3

28

When v is a slice, then v -= X and v = v - X produce very different results. Consider

>>> x = np.arange(6)
>>> v = x[1:4]
>>> v -= 1
>>> v
array([0, 1, 2])
>>> x
array([0, 0, 1, 2, 4, 5])

where v -= 1 updates the slice, and therefore the array that it views, in-place, vs.

>>> x = np.arange(6)
>>> v = x[1:4]
>>> v = v - 1
>>> v
array([0, 1, 2])
>>> x
array([0, 1, 2, 3, 4, 5])

where v = v - 1 resets the variable v while leaving x untouched. To obtain the former result without -=, you'd have to do

v[:] = v - 1
Fred Foo
  • 355,277
  • 75
  • 744
  • 836
  • super helpful, thanks. Could it be changed to v-=100 ? Had to look a couple of times to see the difference... – gebbissimo Apr 29 '20 at 20:21
14

You could get different results from x - y and x -= y if the data types of x and y differ.

For example:

import numpy as np

x = np.array(range(0,6))
y = np.array(np.arange(0,3,0.5))

print x - y
x -= y
print x

This prints out:

[ 0.   0.5  1.   1.5  2.   2.5]
[0 0 1 1 2 2]

It may be worth making sure your arrays' dtypes are exactly as you expect (e.g. you're not inadvertently using integer or float32 arrays instead of float64), paying particular attention to arrays used on the left-hand side of -=.

NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • 2
    +1 even if this turns out not to be the reason; I'd overlooked that possibility entirely, and shouldn't have. – DSM Jan 28 '12 at 17:17
5

+1 to both other answers to this questions. They cover two important differences between = and -= but I wanted to highlight one more. Most of the time x -= y is the same as x[:] = x - y, but not when x and y are slices of the same array. For example:

x = np.ones(10)
y = np.ones(10)

x[1:] += x[:-1]
print x
[  1.   2.   3.   4.   5.   6.   7.   8.   9.  10.]

y[1:] = y[1:] + y[:-1]
print y
[ 1.  2.  2.  2.  2.  2.  2.  2.  2.  2.]
Bi Rico
  • 25,283
  • 3
  • 52
  • 75