A 32-bit float can exactly represent about 7 decimal digits of mantissa. Your number requires more, and therefore cannot be represented exactly.
The mechanics of what happens are as follows:
A 32-bit float has a 24-bit mantissa. Your number requires 27 bits to be represented exactly, so the last three bits are getting truncated (set to zero). The three lowest bits of your number are 0112; these are getting set to 0002. Observe that 0112 is 310.
A 32-bit float can exactly represent about 7 decimal digits of mantissa. Your number requires more, and therefore cannot be represented exactly.
The mechanics of what happens are as follows:
A 32-bit float has a 24-bit mantissa. Your number requires 27 bits to be represented exactly, so the last three bits are getting truncated (set to zero). The three lowest bits of your number are 0112; these are getting set to 0002. Observe that 0112 is 310.
A float32 only has 24 bits of significand precision, which is roughly seven digits (log10(2**24) = 7.22). You're expecting it to store an 8-digit number exactly, which in general is impossible.
Let's see if I can address some of the confusion I'm seeing in the comments.
Make an array:
In [609]: x=np.arange(5)
In [610]: x
Out[610]: array([0, 1, 2, 3, 4])
In [611]: x.dtype
Out[611]: dtype('int32')
The default for arange is to make an int32.
astype is an array method; it can used on any array:
In [612]: x.astype(np.float32)
Out[612]: array([ 0., 1., 2., 3., 4.], dtype=float32)
arange also takes a dtype parameter
In [614]: np.arange(5, dtype=np.float32)
Out[614]: array([ 0., 1., 2., 3., 4.], dtype=float32)
whether it created the int array first and converted it, or made the float32 directly isn't any concern to me. This is a basic operation, done in compiled code.
I can also give it a float stop value, in which case it will give me a float array - the default float type.
In [615]: np.arange(5.0)
Out[615]: array([ 0., 1., 2., 3., 4.])
In [616]: _.dtype
Out[616]: dtype('float64')
zeros is similar; the default dtype is float64, but with a parameter I can change that. Since its primary task with to allocate memory, and it doesn't have to do any calculation, I'm sure it creates the desired dtype right away, without further conversion. But again, this is compiled code, and I shouldn't have to worry about what it is doing under the covers.
In [618]: np.zeros(5)
Out[618]: array([ 0., 0., 0., 0., 0.])
In [619]: _.dtype
Out[619]: dtype('float64')
In [620]: np.zeros(5,dtype=np.float32)
Out[620]: array([ 0., 0., 0., 0., 0.], dtype=float32)
randn involves a lot of calculation, and evidently it is compiled to work with the default float type. It does not take a dtype. But since the result is an array, it can be cast with astype.
In [623]: np.random.randn(3)
Out[623]: array([-0.64520949, 0.21554705, 2.16722514])
In [624]: _.dtype
Out[624]: dtype('float64')
In [625]: __.astype(np.float32)
Out[625]: array([-0.64520949, 0.21554704, 2.16722512], dtype=float32)
Let me stress that astype is a method of an array. It takes the values of the array and produces a new array with the desire dtype. It does not act retroactively (or in-place) on the array itself, or on the function that created that array.
The effect of astype is often (always?) the same as a dtype parameter, but the sequence of actions is different.
In https://stackoverflow.com/a/39625960/901925 I describe a sparse matrix creator that takes a dtype parameter, and implements it with an astype method call at the end.
When you do calculations such as dot or *, it tries to match the output dtype with inputs. In the case of mixed types it goes with the higher precision alternative.
In [642]: np.arange(5,dtype=np.float32)*np.arange(5,dtype=np.float64)
Out[642]: array([ 0., 1., 4., 9., 16.])
In [643]: _.dtype
Out[643]: dtype('float64')
In [644]: np.arange(5,dtype=np.float32)*np.arange(5,dtype=np.float32)
Out[644]: array([ 0., 1., 4., 9., 16.], dtype=float32)
There are casting rules. One way to look those up is with can_cast function:
In [649]: np.can_cast(np.float64,np.float32)
Out[649]: False
In [650]: np.can_cast(np.float32,np.float64)
Out[650]: True
It is possible in some calculations that it will cast the 32 to 64, do the calculation, and then cast back to 32. The purpose would be to avoid rounding errors. But I don't know how you find that out from the documentation or tests.
arr1 = np.array([25, 56, 12, 85, 34, 75])
arr2 = np.array([42, 3, 86, 32, 856, 46])
arr1.astype(np.complex)
print (arr1)
print(type(arr1[0]))
print(arr1.astype(np.complex))
arr2 = np.array(arr2,dtype='complex')
print(arr2)
print(type(arr2[0]))
OUTPUT for above
[25 56 12 85 34 75]
<class 'numpy.int64'>
[25.+0.j 56.+0.j 12.+0.j 85.+0.j 34.+0.j 75.+0.j]
[ 42.+0.j 3.+0.j 86.+0.j 32.+0.j 856.+0.j 46.+0.j]
<class 'numpy.complex128'>
It can be seen that astype changes the type temporally as we do in normal type casting but where as the generic method changes the type permanently
The IEEE 754-2008 16-bit base 2 format, aka binary16, doesn't give you a lot of precision. What do you expect from 16 bits? :) 1 bit is the sign bit, 5 bits are used for the exponent, and that leaves 10 bits to store the normalised 11 bit mantissa, so anything > 2**11 == 2048 has to be quantized.
According to Wikipedia, integers between 4097 and 8192 round to a multiple of 4, and integers between 8193 and 16384 round to a multiple of 8.
Tensorflow requires float16 and produces an error for float32. You can use what was suggested by Reti43:
np.float16(a)
Out[102]: array([8192.], dtype=float16)
I'm surprised that a useless reply has been upvoted so high. I know that moderators request to mark as the best answer the one which was upvoted the highest, but an question author is not obliged to do this. There are a number of people who just gather points here, and do not care about actually replying to a request. They might upvote themselves under different names.
- If the dataframe (say
df) wholly consists offloat64dtypes, you can do:
df = df.astype('float32')
- Only if some columns are
float64, then you'd have to select those columns and change their dtype:
# Select columns with 'float64' dtype
float64_cols = list(df.select_dtypes(include='float64'))
# The same code again calling the columns
df[float64_cols] = df[float64_cols].astype('float32')
Try this:
df[df.select_dtypes(np.float64).columns] = df.select_dtypes(np.float64).astype(np.float32)