The numbers are (most likely) the same, it's just a matter of how the objects are formatted as strings.
>>> numpy.array([75.09], dtype="float32")[0] == numpy.float32(75.09)
True
The problem (as you may already know) is that 75.09 seems to require a lot of precision, maybe even infinite (I didn't do the math, more about it here).
If you want to have consistent text output just use your own string formatting.
>>> a = numpy.array([75.09], dtype="float32")
>>> b = numpy.float32(75.09)
>>> print 'a: [', ','.join('{:.6f}'.format(ai) for ai in a), '] b:','{:.6f}'.format(b)
a: [ 75.089996 ] b: 75.089996
>>> print 'a: [', ','.join('{:.8f}'.format(ai) for ai in a), '] b:','{:.8f}'.format(b)
a: [ 75.08999634 ] b: 75.08999634
The display of the numbers is different because they are printed as a NumPy array (1) and and float (2). Try to print the first array member numpy.array([75.09], dtype="float32")[0].
Comments about the finite precision of floating point numbers are also to take into account :-) Almost never will you find equality in floating point numerics.
Looks like an unfortunate accident: someone decided that dtype(None) would "default" to float (though dtype() is an error). Then someone else wrote dtype.__eq__ such that it converts its second argument to a dtype before comparing. So dtype(float) == None is dtype(float) == dtype(None) which is true.
You can see a comment in the source code here: descriptor.c#L1217
- Get typenum from an object -- None goes to NPY_DEFAULT_TYPE
And of course NPY_DEFAULT_TYPE is float (at least usually).
As for the __eq__ operator, it's here: descriptor.c#L3317. It does what I outlined:
if (!PyArray_DescrCheck(other)) {
if (PyArray_DescrConverter(other, &new) == NPY_FAIL) {
return NULL;
}
}
So that's a conversion from whatever is on the right-hand side of == to a dtype object, via the converter function mentioned before, which turns None into dtype(float).
Edit: I found this pretty interesting and it seems like an accident, so I created a patch and submitted to the maintainers: https://github.com/numpy/numpy/pull/4532 .
if you want to compare an arbitrary object against exactly None in python you need to use:
object is None
Like in this case any object may override its comparison operator to not do what you are expecting.
As for why, dtype('float64') is equivalent to None in the context of dtypes in the same way dtypes are equivalent to typestrings
np.dtype('i4') == 'i4'
True
Equality is not identity.
As for why dtype(None) == dtype('float64'), many functions in numpy have dtype=None keyword arguments. In most cases this means default dtype which is dtype(None). An example is np.zeros. But there are exceptions, e.g. when the dtype can be inferred from the arguments, like in the case of np.arange(10) where the default dtype will be of integer type (np.intp I think).