Wrap out-of-range float-to-integer astype casts to match NumPy - #3033
Draft
antonwolfy wants to merge 2 commits into
Draft
Wrap out-of-range float-to-integer astype casts to match NumPy#3033antonwolfy wants to merge 2 commits into
antonwolfy wants to merge 2 commits into
Conversation
Casting an out-of-range floating-point value to an integer type is undefined behavior in C++. SYCL devices resolve it by saturating to the destination's min/max, while NumPy emits a plain C cast that, for narrow integer targets, truncates toward zero and wraps modulo the destination width (e.g. float32(128) -> int8(-128)). dpnp targets NumPy compatibility, but convert_impl only normalized this for unsigned destinations, so signed narrow targets saturated instead of wrapping. This inconsistency surfaced as an Array API conformance failure in linalg.trace with an int8 output dtype, where the element-wise astype path saturated while the reduction path wrapped. Generalize convert_impl to funnel every float-to-integer conversion through a wider signed integer, relying on the well-defined integer narrowing to perform the modular wrap for both signed and unsigned narrow targets. Add a regression test covering signed and unsigned targets and reuse the shared dtype lists in the ctor tests.
Contributor
|
Array API standard conformance tests for dpnp=0.21.0dev5=py314ha0e2e8e_5 ran successfully. |
Collaborator
Contributor
|
View rendered docs @ https://intelpython.github.io/dpnp/pull/3033/index.html |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Casting an out-of-range floating-point value to an integer type is undefined behavior in C++. SYCL devices resolve it by saturating to the destination's min/max, whereas NumPy emits a plain C cast that, for narrow integer targets, truncates toward zero and wraps modulo the destination width (e.g.
float32(128)becomesint8(-128)).convert_impl(used byastypeand every copy-and-cast kernel) only normalized this to NumPy's wrapping behavior for unsigned destinations. Signed narrow integer targets fell through to a rawstatic_castand therefore saturated on device, diverging from NumPy. The same inconsistency showed up within a single operation:dpnp.tensor.linalg.tracewith anint8output dtype produced different results depending on whether the value went through the element-wiseastypepath (saturated) or the reduction path (wrapped).This PR generalizes the float-to-integer branch of
convert_implto funnel every conversion through a wider signed integer, relying on the well-defined integer narrowing to perform the modular wrap for both signed and unsigned narrow integer targets. 64-bit destinations keep their existing handling (unsigned routes negatives throughint64; signed casts directly).