How are the sign bits determined when initializing an ndarray from empty memory?
>>> np.random.randn(3,3)
array([[-0.35557367, -0.0561576 , -1.84722985],
[ 0.89342124, -0.50871646, 1.31368413],
[ 0.0062188 , 1.62968789, 0.72367089]])
>>> np.empty((3,3))
array([[0.35557367, 0.0561576 , 1.84722985],
[0.89342124, 0.50871646, 1.31368413],
[0.0062188 , 1.62968789, 0.72367089]])
These float values initialized from empty memory have lost their signs†. Why is that?
†Note: this result relies on implementation detail of memory re-use. The question asks what the implementation is doing.
In Python, the numpy. empty() function is used to return new array of a given shape and type. It has random values and uninitialized entries.
empty has nothing to do with creating an array that is "empty" in the sense of having no elements. It just means the array doesn't have its values initialized (i.e., they are unpredictable and depend on whatever happens to be in the memory allocated for the array).
The second way to declare an empty array in Python is by creating a list and multiplying it by the number(length of the array) to create an empty array. This will create an empty array of size 4. print(myarr) will result in the following output. Additionally, we can create an empty array using NumPy.
numpy.empty
isn't clearing the sign bits manually or anything. The sign bits are just whatever garbage happens to be left in those bits of the malloc
return value. The effect you're seeing is due to a numpy.absolute
call somewhere else.
The thing is, numpy.empty
isn't reusing the randn
return value's buffer. After all, the randn
return value is still alive when empty
creates its array, due to the _
variable.
numpy.empty
is reusing the buffer of an array created in the process of stringifying the first array. I believe it's this one:
def fillFormat(self, data):
# only the finite values are used to compute the number of digits
finite_vals = data[isfinite(data)]
# choose exponential mode based on the non-zero finite values:
abs_non_zero = absolute(finite_vals[finite_vals != 0])
...
See that absolute
call? That's the one.
Here's some additional testing that supports that conclusion:
>>> a = numpy.random.randn(3, 3)
>>> b = numpy.arange(-5, 4, dtype=float)
>>> c = numpy.arange(-5, 13, 2, dtype=float)
>>> a
array([[-0.96810932, 0.86091026, -0.32675013],
[-1.23458136, 0.56151178, -0.37409982],
[-1.71348979, 0.64170792, -0.20679512]])
>>> numpy.empty((3, 3))
array([[ 0.96810932, 0.86091026, 0.32675013],
[ 1.23458136, 0.56151178, 0.37409982],
[ 1.71348979, 0.64170792, 0.20679512]])
>>> b
array([-5., -4., -3., -2., -1., 0., 1., 2., 3.])
>>> numpy.empty((3, 3))
array([[ 0.96810932, 0.86091026, 0.32675013],
[ 1.23458136, 0.56151178, 0.37409982],
[ 1.71348979, 0.64170792, 0.20679512]])
>>> c
array([ -5., -3., -1., 1., 3., 5., 7., 9., 11.])
>>> numpy.empty((3, 3))
array([[ 5., 3., 1.],
[ 1., 3., 5.],
[ 7., 9., 11.]])
>>> numpy.array([1.0, 0, 2, 3, 4, 5, 6, 7, 8, 9])
array([ 1., 0., 2., 3., 4., 5., 6., 7., 8., 9.])
>>> numpy.empty((3, 3))
array([[ 1., 2., 3.],
[ 4., 5., 6.],
[ 7., 8., 9.]])
The numpy.empty
results are affected by printing a
and c
, rather than by the process of creating those arrays. b
has no effect, because it has 8 nonzero elements. The final array([1.0, 0, 2, ...])
has an effect, because even though it has 10 elements, exactly 9 of them are nonzero.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With