Skip to content

ENH: add a casting option 'same_value' and use it in np.astype #29129

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
cb8ea97
start implementing same_value casting
mattip Feb 17, 2025
3859a73
work through more places that check 'cast', add a TODO
Feb 17, 2025
9dc63a5
add a test, percolate casting closer to inner loops
mattip May 15, 2025
7cad6af
use SAME_VALUE_CAST flag for one inner loop variant
mattip May 29, 2025
03e9ceb
aligned test of same_value passes. Need more tests
mattip Jun 1, 2025
93b8bce
handle unaligned casting with 'same_value'
mattip Jun 1, 2025
87e2487
extend tests to use source-is-complex
mattip Jun 1, 2025
9aa1e5a
fix more interfaces to pass casting around, disallow using 'same_valu…
mattip Jun 2, 2025
953714e
raise in places that have a kwarg casting, besides np.astype
mattip Jun 2, 2025
cd3e144
refactor based on review comments
mattip Jun 9, 2025
6d6b045
CHAR_MAX,MIN -> SCHAR_MAX,MIN
mattip Jul 21, 2025
1293657
copy context flags
mattip Jul 22, 2025
d151c91
add 'same_value' to typing stubs
mattip Jul 23, 2025
6254ae5
document new feature
mattip Jul 24, 2025
6922b35
test, check exact float->int casting: refactor same_value check into …
mattip Jul 24, 2025
a323a4b
enable astype same_value casting for scalars
mattip Jul 24, 2025
aec8ea1
typo
mattip Jul 24, 2025
26c0fa1
fix ptr-to-src_value -> value casting errors
mattip Jul 25, 2025
0846081
fix linting and docs, ignore warning better
mattip Jul 25, 2025
76e01c1
gcc warning is different
mattip Jul 25, 2025
963ea05
fixes from review, typos
mattip Jul 26, 2025
4a9a498
fix compile warning ignore and make filter in tests more specific, di…
mattip Jul 27, 2025
10c4493
fix warning filters
mattip Jul 28, 2025
58a0a09
emit PyErr inside the loop
mattip Jul 31, 2025
64b8747
macOS can emit FPEs when touching NAN
mattip Jul 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
aligned test of same_value passes. Need more tests
  • Loading branch information
mattip committed Jul 21, 2025
commit 03e9cebda7785c17a3f3600f21f313e38ecda6f9
72 changes: 65 additions & 7 deletions numpy/_core/src/multiarray/lowlevel_strided_loops.c.src
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <numpy/arrayobject.h>
#include <numpy/npy_cpu.h>
#include <numpy/halffloat.h>
#include <float.h>

#include "lowlevel_strided_loops.h"
#include "array_assign.h"
Expand Down Expand Up @@ -742,6 +743,7 @@ NPY_NO_EXPORT PyArrayMethod_StridedLoop *
* #is_float1 = 0*12, 1, 0, 0, 1, 0, 0#
* #is_double1 = 0*13, 1, 0, 0, 1, 0#
* #is_complex1 = 0*15, 1*3#
* #is_unsigned1 = 1*6, 0*12#
*/

/**begin repeat1
Expand All @@ -766,6 +768,16 @@ NPY_NO_EXPORT PyArrayMethod_StridedLoop *
* npy_byte, npy_short, npy_int, npy_long, npy_longlong,
* _npy_half, npy_float, npy_double, npy_longdouble,
* npy_float, npy_double, npy_longdouble#
* #type2max = 0,
* UCHAR_MAX, USHRT_MAX, UINT_MAX, ULONG_MAX, ULLONG_MAX,
* CHAR_MAX, SHRT_MAX, INT_MAX, LONG_MAX, LLONG_MAX,
* 65500, FLT_MAX, DBL_MAX, LDBL_MAX,
* FLT_MAX, DBL_MAX, LDBL_MAX#
* #type2min = 0,
* 0, 0, 0, 0, 0,
* CHAR_MIN, SHRT_MIN, INT_MIN, LONG_MIN, LLONG_MIN,
* -65500, -FLT_MAX, -DBL_MAX, -LDBL_MAX,
* -FLT_MAX, -DBL_MAX, -LDBL_MAX#
* #is_bool2 = 1, 0*17#
* #is_emu_half2 = 0*11, EMULATED_FP16, 0*6#
* #is_native_half2 = 0*11, NATIVE_FP16, 0*6#
Expand Down Expand Up @@ -810,7 +822,7 @@ NPY_NO_EXPORT PyArrayMethod_StridedLoop *

/* Determine an appropriate casting conversion function */
#if @is_emu_half1@

# define _TO_RTYPE1(x) npy_half_to_float(x)
# if @is_float2@
# define _CONVERT_FN(x) npy_halfbits_to_floatbits(x)
# elif @is_double2@
Expand All @@ -824,6 +836,7 @@ NPY_NO_EXPORT PyArrayMethod_StridedLoop *
# endif

#elif @is_emu_half2@
# define _TO_RTYPE1(x) (@rtype1@)(x)

# if @is_float1@
# define _CONVERT_FN(x) npy_floatbits_to_halfbits(x)
Expand All @@ -838,6 +851,7 @@ NPY_NO_EXPORT PyArrayMethod_StridedLoop *
# endif

#else
# define _TO_RTYPE1(x) (@rtype1@)(x)

# if @is_bool2@ || @is_bool1@
# define _CONVERT_FN(x) ((npy_bool)(x != 0))
Expand Down Expand Up @@ -899,7 +913,9 @@ static GCC_CAST_OPT_LEVEL int
#endif

/*printf("@prefix@_cast_@name1@_to_@name2@\n");*/
#if !@is_bool2@
int same_value_casting = ((context->flags & NPY_SAME_VALUE_CASTING) == NPY_SAME_VALUE_CASTING);
#endif

while (N--) {
#if @aligned@
Expand All @@ -916,36 +932,77 @@ static GCC_CAST_OPT_LEVEL int
# if @is_complex2@
dst_value[0] = _CONVERT_FN(src_value[0]);
dst_value[1] = _CONVERT_FN(src_value[1]);
if (same_value_casting) {
if ((dst_value[0] != src_value[0]) || (dst_value[1] != src_value[1])){
return NPY_SAME_VALUE_OVERFLOW;
}
}
# elif !@aligned@
# if @is_bool2@
dst_value = _CONVERT_FN(src_value[0]) || _CONVERT_FN(src_value[1]);
# else
dst_value = _CONVERT_FN(src_value[0]);
if (same_value_casting) {
if (dst_value != src_value[0]){
return NPY_SAME_VALUE_OVERFLOW;
}
}
# endif
# else
# if @is_bool2@
*(_TYPE2 *)dst = _CONVERT_FN(src_value[0]) || _CONVERT_FN(src_value[1]);
# else
*(_TYPE2 *)dst = _CONVERT_FN(src_value[0]);
if (same_value_casting) {
if (*(_TYPE2 *)dst != src_value[0]){
return NPY_SAME_VALUE_OVERFLOW;
}
}
# endif
# endif
#else
#else // @is_complex1@
# if @is_complex2@
# if !@aligned@
dst_value[0] = _CONVERT_FN(src_value);
# else
dst_value[0] = _CONVERT_FN(*(_TYPE1 *)src);
# endif
dst_value[1] = 0;
if (same_value_casting) {
# if !@aligned@
if ((@rtype2@)dst_value[0] != src_value){
# else
if ((@rtype2@)dst_value[0] != *((_TYPE1 *)src)){
# endif
return NPY_SAME_VALUE_OVERFLOW;
}
}
# elif !@aligned@
dst_value = _CONVERT_FN(src_value);
# if !@is_bool2@
if (same_value_casting) {
if (src_value > @type2max@ || src_value < @type2min@) {
return NPY_SAME_VALUE_OVERFLOW;
}
if (dst_value != src_value){
return NPY_SAME_VALUE_OVERFLOW;
}
}
# endif // @is_bool2@
# else
*(_TYPE2 *)dst = _CONVERT_FN(*(_TYPE1 *)src);
if (same_value_casting) {
if (*(_TYPE2 *)dst != *(_TYPE1 *)src) {
return NPY_SAME_VALUE_OVERFLOW;
}
*(_TYPE2 *)dst = _CONVERT_FN(*(_TYPE1 *)src);
# if !@is_bool2@
if (same_value_casting) {
if (_TO_RTYPE1(*((_TYPE1 *)src)) > @type2max@) {
return NPY_SAME_VALUE_OVERFLOW;
}
# if !@is_unsigned1@
if (_TO_RTYPE1(*((_TYPE1 *)src)) < @type2min@) {
return NPY_SAME_VALUE_OVERFLOW;
}
# endif
}
# endif // @is_bool2@
# endif
#endif

Expand Down Expand Up @@ -983,6 +1040,7 @@ static GCC_CAST_OPT_LEVEL int
#undef _CONVERT_FN
#undef _TYPE2
#undef _TYPE1
#undef _TO_RTYPE1

#endif

Expand Down
5 changes: 0 additions & 5 deletions numpy/_core/src/multiarray/methods.c
Original file line number Diff line number Diff line change
Expand Up @@ -843,11 +843,6 @@ array_astype(PyArrayObject *self,
int success;
if (casting == NPY_SAME_VALUE_CASTING) {
success = PyArray_AssignArray(ret, self, NULL, casting);
if (success < 0) {
printf("error in PyArray_AssignArray\n");
//PyErr_SetString(PyExc_RuntimeError, "error when casting");
//npy_set_invalid_cast_error(PyArray_DESCR(self), dtype, casting, 0);
}
} else {
success = PyArray_AssignArray(ret, self, NULL, NPY_UNSAFE_CASTING);
}
Expand Down
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy