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.

Answer from NPE on Stack Overflow
🌐
NumPy
numpy.org › doc › stable › user › basics.types.html
Data types — NumPy v2.4 Manual
To convert the type of an array, use the .astype() method. For example: ... Note that, above, we could have used the Python float object as a dtype instead of numpy.float64. NumPy knows that int refers to numpy.int_, bool means numpy.bool, that float is numpy.float64 and complex is numpy.complex128.
🌐
NumPy
numpy.org › doc › stable › reference › generated › numpy.ndarray.astype.html
numpy.ndarray.astype — NumPy v2.4 Manual
June 22, 2021 - ‘same_kind’ means only safe ... to float32, are allowed. ‘unsafe’ means any data conversions may be done. ‘same_value’ means any data conversions may be done, but the values must not change, including rounding of floats or overflow of ints · New in version 2.4: Support for 'same_value' was added. ... If True, then sub-classes will be passed-through (default), otherwise the returned array will be forced to be a base-class array. ... By default, astype always returns ...
🌐
Note.nkmk.me
note.nkmk.me › home › python › numpy
NumPy: astype() to change dtype of an array | note.nkmk.me
February 4, 2024 - a = np.array([1, 2, 3]) print(a) print(a.dtype) # [1 2 3] # int64 a_float = a.astype(np.float32) print(a_float) print(a_float.dtype) # [1. 2. 3.] # float32 print(a) print(a.dtype) # [1 2 3] # int64 · source: numpy_astype.py · As mentioned above, dtype can also be specified as a type name string, type code string, or Python type.
🌐
PyTorch Forums
discuss.pytorch.org › vision
Beginner question about astype("float32") and float() - vision - PyTorch Forums
December 14, 2019 - In the customized dataset file, in a multi-label context, 1/Is there a reason for the use of float() in addition to .astype(“float32”) in this code? 2/And why cast the labels to float and not leave it as a numpy array of integers(one-hot encoded)? labels = torch.from_numpy( item.iloc[1:].values.astype(“float32”)).float() Thanks in advance
🌐
JAX Documentation
docs.jax.dev › en › latest › _autosummary › jax.numpy.astype.html
jax.numpy.astype — JAX documentation
>>> x = jnp.array([0, 1, 2, 3]) >>> x Array([0, 1, 2, 3], dtype=int32) >>> x.astype('float32') Array([0.0, 1.0, 2.0, 3.0], dtype=float32) >>> y = jnp.array([0.0, 0.5, 1.0]) >>> y.astype(int) # truncates fractional values Array([0, 0, 1], dtype=int32) Contents
🌐
Pandas
pandas.pydata.org › docs › reference › api › pandas.DataFrame.astype.html
pandas.DataFrame.astype — pandas 3.0.2 documentation
>>> ser = pd.Series([1, 2], dtype="int32") >>> ser 0 1 1 2 dtype: int32 >>> ser.astype("int64") 0 1 1 2 dtype: int64
🌐
Python⇒Speed
pythonspeed.com › articles › float64-float32-precision
The problem with float32: you only get 16 million values
February 1, 2023 - And as it turns out, float32s can represent 16 million different values at a precision of $1,000,000 just fine: >>> values = np.arange(0, 16_000_000_000_000, step=1_000_000) >>> values[-5:] array([15999995000000, 15999996000000, 15999997000000, 15999998000000, 15999999000000]) >>> values[-5:].astype(np.float32) array([1.5999995e+13, 1.5999996e+13, 1.5999997e+13, 1.5999998e+13, 1.5999999e+13], dtype=float32)
Find elsewhere
🌐
NumPy
numpy.org › devdocs › reference › generated › numpy.ndarray.astype.html
numpy.ndarray.astype — NumPy v2.5.dev0 Manual
‘same_kind’ means only safe ... to float32, are allowed. ‘unsafe’ means any data conversions may be done. ‘same_value’ means any data conversions may be done, but the values must not change, including rounding of floats or overflow of ints · New in version 2.4: Support for 'same_value' was added. ... If True, then sub-classes will be passed-through (default), otherwise the returned array will be forced to be a base-class array. ... By default, astype always returns ...
🌐
Vultr Docs
docs.vultr.com › python › third-party › numpy › array › astype
Python Numpy array astype() - Convert Data Type | Vultr Docs
November 8, 2024 - import numpy as np high_precision = np.array([1.123456789, 2.987654321], dtype=np.float64) low_precision = high_precision.astype(np.float32) print("High precision:", high_precision) print("Low precision:", low_precision) Explain Code
Top answer
1 of 3
13

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.

2 of 3
3
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

🌐
NumPy
numpy.org › doc › 2.1 › reference › generated › numpy.ndarray.astype.html
numpy.ndarray.astype — NumPy v2.1 Manual
‘same_kind’ means only safe ... to float32, are allowed. ‘unsafe’ means any data conversions may be done. ... If True, then sub-classes will be passed-through (default), otherwise the returned array will be forced to be a base-class array. ... By default, astype always returns ...
🌐
Note.nkmk.me
note.nkmk.me › home › python › pandas
pandas: How to use astype() to cast dtype of DataFrame | note.nkmk.me
August 9, 2023 - df = pd.DataFrame({'a': [11, 21, 31], 'b': [12, 22, 32], 'c': [13, 23, 33]}) print(df) # a b c # 0 11 12 13 # 1 21 22 23 # 2 31 32 33 print(df.dtypes) # a int64 # b int64 # c int64 # dtype: object df_fcol = df.astype({'a': float}) print(df_fcol) # a b c # 0 11.0 12 13 # 1 21.0 22 23 # 2 31.0 32 33 print(df_fcol.dtypes) # a float64 # b int64 # c int64 # dtype: object df_fcol2 = df.astype({'a': 'float32', 'c': 'int8'}) print(df_fcol2) # a b c # 0 11.0 12 13 # 1 21.0 22 23 # 2 31.0 32 33 print(df_fcol2.dtypes) # a float32 # b int64 # c int8 # dtype: object ·
🌐
NumPy
numpy.org › doc › 1.18 › user › basics.types.html
Data types — NumPy v1.18 Manual
>>> np.array([1, 2, 3], dtype='f') array([ 1., 2., 3.], dtype=float32) We recommend using dtype objects instead. To convert the type of an array, use the .astype() method (preferred) or the type itself as a function. For example: >>> z.astype(float) array([ 0., 1., 2.]) >>> np.int8(z) array([0, 1, 2], dtype=int8) Note that, above, we use the Python float object as a dtype.
🌐
NumPy
numpy.org › doc › 2.0 › reference › generated › numpy.ndarray.astype.html
numpy.ndarray.astype — NumPy v2.0 Manual
‘same_kind’ means only safe ... to float32, are allowed. ‘unsafe’ means any data conversions may be done. ... If True, then sub-classes will be passed-through (default), otherwise the returned array will be forced to be a base-class array. ... By default, astype always returns ...
🌐
Programiz
programiz.com › python-programming › numpy › methods › astype
NumPy astype()
# casting with 'no' doesn't allow casting to any other data type array2 = array1.astype(array1.dtype, casting='no') # casting with 'equiv' allows casting to equivalent data types array3 = array1.astype('<i4', casting='equiv') #cCasting with 'safe' allows casting to safe data types preserving precision array4 = array1.astype(np.float64, casting='safe') # casting with 'same_kind' allows casting to data types of the same kind array5 = array1.astype(np.int32, casting='same_kind') # casting with 'unsafe' allows casting to any data type without checks array6 = array1.astype(str, casting='unsafe') print("Array with 'no' casting:", array2) print("Array with 'equiv' casting:", array3) print("Array with 'safe' casting:", array4) print("Array with 'same_kind' casting:", array5) print("Array with 'unsafe' casting:", array6)
🌐
GitHub
github.com › numpy › numpy › issues › 12721
np.array(..., dtype=np.float32).astype(np.float16) doesn't handle denorms properly · Issue #12721 · numpy/numpy
January 11, 2019 - The following interpreter sequence shows such a case that is properly handled by the float64->float16 conversion, but not by the float32->float16 conversion (see the last line below). $ python3 Python 3.5.2 (default, Nov 12 2018, 13:43:14) [GCC 5.4.0 20160609] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import numpy as np >>> np.__version__ '1.14.3' >>> '%.40f' % np.array([2**-24]).astype(np.float64)[0] '0.0000000596046447753906250000000000000000' >>> '%.40f' % np.array([2**-24]).astype(np.float32)[0] '0.0000000596046447753906250000000000000000' >>> '%.4
Author   DickJC123