3

Today I have noticed strange behavior of Numpy/Scipy arrays. It looks like adding array cell with integer inside to float can have two different results, depending on the variable to which the result is assigned. Instead of long explanations, below I present the code:

import scipy as sp
array_int = sp.array([[0], [0]])
float_operand = 0.1
print array_int[0, 0] + float_operand #gives 0.1

But

import scipy as sp
array_int = sp.array([[0], [0]])
float_operand = 0.1
array_int[0, 0] = array_int[0, 0] + float_operand 
print array_int[0, 0] #gives 0

I could understand if this kind of behavior was inherited from Python, but:

In contrary to behavior of "bare" Python (2.7):

integer_for_sure = int(0) 
integer_for_sure = integer_for_sure + 0.1
print integer_for_sure #gives 0.1 as expected

Is this kind of feature somwhere documented? Has anybody encounterd it before?

2
  • 1
    As a side note, it's often clearer, simpler, and more efficient to use zeros((2, 1)) instead of constructing a 2x1 list of lists of zeros to pass to array (especially when you get a lot bigger than 2x1). Commented Nov 18, 2014 at 21:58
  • 2
    Coding recommendation: Use import numpy as np (and use the np prefix) instead of import scipy as sp. The scipy namespace includes the numpy namespace for historical reasons, but it is more explicit (and removes a dependency on scipy if all you really need is numpy) to import the numpy names directly from numpy. Commented Nov 18, 2014 at 22:07

2 Answers 2

3

Henry Keiter has explained it well enough. I would only add one technical detail.

In contrast to the regular assignment which simply rewires integer_for_sure to refer to the float object that results from integer_for_sure + 0.1, thus changing the type of the variable, assignment to array elements such as

array_int[0, 0] = array_int[0, 0] + float_operand

is actually syntactic sugar for the more verbose

array_int.__setitem__((0,0), array_int.__getitem__((0,0)) + float_operand)

(this applies to old-style classes; it looks a bit different for new-style classes but the idea stays the same)

The __setitem__ method for each array type performs a typecast of its value argument to the type of the array. The actual C code that implements the assignment is kind of ugly and involves a custom preprocessor.

On the other side

print array_int[0, 0] + float_operand

is

print array_int.__getitem__((0,0)) + float_operand

i.e. it fetches the integer value from array_int, sums it with float_operand and the resulting float object is passed to print. There is no intermediate assignment to array_int[0, 0] and therefore no typecast.

Sign up to request clarification or add additional context in comments.

Comments

3

This is not a behavior "inherited from Python" -- as you can see, adding a float to an int in pure Python produces a float result. Rather, you can think of this behavior as "inherited from C." Unlike Python lists, numpy arrays have strong element types. The array constructor includes a telltale optional keyword argument that alludes to this:

dtype : data-type, optional

The desired data-type for the array. If not given, then the type will be determined as the minimum type required to hold the objects in the sequence. This argument can only be used to ‘upcast’ the array.

The emphasis is mine. When you create an array with np.array([[0], [0]]), you get a two-dimentional integer array, because an integer is the smallest datatype that can contain 0. Once the integer array is created, it may only contain integers. If you attempt to insert a float, it will be cast to an integer as you noticed in order to be placed in the array.


If you want to store floats in the array eventually, you need to initialize your array as a float array ('upcast' it). This can be accomplished by using the dtype argument mentioned above, or simply by putting a float value into the initial array (e.g. 0.0 instead of the integer 0).

import scipy as sp
array_int = sp.array([[0], [0]])
array_float = sp.array([[0.0], [0]])  # Note the extra .0 to make one element a float

array_int[0, 0] = array_int[0, 0] + 0.1
print array_int[0, 0] # 0

array_float[0, 0] = array_float[0, 0] + 0.1
print array_float[0, 0] # 0.1

Comments

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.