Skip to content

Commit adca8ce

Browse files
honnokgryte
andauthored
Align casting methods with Python behaviour (#497)
* Introduce conservative `x.__complex__()` * Don't hard require same-kind arrays for builtin cast methods * Align casting methods with Python behaviour * Remove unnecessary `__int__` note on out-of-scope beyond bounds * `__index__`: leave bool arrays unspecified and restrict out to `int` * Update `__complex__` note with complex results * Clarify `__bool__` note language * "real-valued" -> "numeric" input array in `__bool__` note * Clearer and spec-consistent language for casting methods Co-authored-by: Athan <[email protected]> * Special case neg zeros in `x.__int__()` * Special cases over note in `x.__bool__()` * Special cases over notes for boolean cross-kind casting * Add missing backticks * Update copy * Add special cases for real-valued floating-point operands Co-authored-by: Athan <[email protected]>
1 parent 7d9752f commit adca8ce

File tree

2 files changed

+77
-7
lines changed

2 files changed

+77
-7
lines changed

Diff for: spec/API_specification/array_api/array_object.py

+76-7
Original file line numberDiff line numberDiff line change
@@ -265,19 +265,58 @@ def __array_namespace__(self: array, /, *, api_version: Optional[str] = None) ->
265265

266266
def __bool__(self: array, /) -> bool:
267267
"""
268-
Converts a zero-dimensional boolean array to a Python ``bool`` object.
268+
Converts a zero-dimensional array to a Python ``bool`` object.
269+
270+
**Special cases**
271+
272+
For real-valued floating-point operands,
273+
274+
- If ``self`` is ``NaN``, the result is ``True``.
275+
- If ``self`` is either ``+infinity`` or ``-infinity``, the result is ``True``.
276+
- If ``self`` is either ``+0`` or ``-0``, the result is ``False``.
277+
278+
For complex floating-point operands, special cases must be handled as if the operation is implemented as the logical AND of ``bool(real(self))`` and ``bool(imag(self))``.
269279
270280
Parameters
271281
----------
272282
self: array
273-
zero-dimensional array instance. Must have a boolean data type.
283+
zero-dimensional array instance.
274284
275285
Returns
276286
-------
277287
out: bool
278288
a Python ``bool`` object representing the single element of the array.
279289
"""
280290

291+
def __complex__(self: array, /) -> complex:
292+
"""
293+
Converts a zero-dimensional array to a Python ``complex`` object.
294+
295+
**Special cases**
296+
297+
For boolean operands,
298+
299+
- If ``self`` is ``True``, the result is ``1+0j``.
300+
- If ``self`` is ``False``, the result is ``0+0j``.
301+
302+
For real-valued floating-point operands,
303+
304+
- If ``self`` is ``NaN``, the result is ``NaN + NaN j``.
305+
- If ``self`` is ``+infinity``, the result is ``+infinity + 0j``.
306+
- If ``self`` is ``-infinity``, the result is ``-infinity + 0j``.
307+
- If ``self`` is a finite number, the result is ``self + 0j``.
308+
309+
Parameters
310+
----------
311+
self: array
312+
zero-dimensional array instance.
313+
314+
Returns
315+
-------
316+
out: complex
317+
a Python ``complex`` object representing the single element of the array instance.
318+
"""
319+
281320
def __dlpack__(self: array, /, *, stream: Optional[Union[int, Any]] = None) -> PyCapsule:
282321
"""
283322
Exports the array for consumption by :func:`~array_api.from_dlpack` as a DLPack capsule.
@@ -413,12 +452,22 @@ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array:
413452

414453
def __float__(self: array, /) -> float:
415454
"""
416-
Converts a zero-dimensional floating-point array to a Python ``float`` object.
455+
Converts a zero-dimensional array to a Python ``float`` object.
456+
457+
.. note::
458+
Casting integer values outside the representable bounds of Python's float type is not specified and is implementation-dependent.
459+
460+
**Special cases**
461+
462+
For boolean operands,
463+
464+
- If ``self`` is ``True``, the result is ``1``.
465+
- If ``self`` is ``False``, the result is ``0``.
417466
418467
Parameters
419468
----------
420469
self: array
421-
zero-dimensional array instance. Must have a real-valued floating-point data type.
470+
zero-dimensional array instance. Should have a real-valued or boolean data type. If ``self`` has a complex floating-point data type, the function must raise a ``TypeError``.
422471
423472
Returns
424473
-------
@@ -561,7 +610,7 @@ def __index__(self: array, /) -> int:
561610
Parameters
562611
----------
563612
self: array
564-
zero-dimensional array instance. Must have an integer data type.
613+
zero-dimensional array instance. Should have an integer data type. If ``self`` has a floating-point data type, the function must raise a ``TypeError``.
565614
566615
Returns
567616
-------
@@ -571,17 +620,37 @@ def __index__(self: array, /) -> int:
571620

572621
def __int__(self: array, /) -> int:
573622
"""
574-
Converts a zero-dimensional integer array to a Python ``int`` object.
623+
Converts a zero-dimensional array to a Python ``int`` object.
624+
625+
**Special cases**
626+
627+
For boolean operands,
628+
629+
- If ``self`` is ``True``, the result is ``1``.
630+
- If ``self`` is ``False``, the result is ``0``.
631+
632+
For floating-point operands,
633+
634+
- If ``self`` is a finite number, the result is the integer part of ``self``.
635+
- If ``self`` is ``-0``, the result is ``0``.
575636
576637
Parameters
577638
----------
578639
self: array
579-
zero-dimensional array instance. Must have an integer data type.
640+
zero-dimensional array instance. Should have a real-valued or boolean data type. If ``self`` has a complex floating-point data type, the function must raise a ``TypeError``.
580641
581642
Returns
582643
-------
583644
out: int
584645
a Python ``int`` object representing the single element of the array instance.
646+
647+
648+
**Raises**
649+
650+
For floating-point operands,
651+
652+
- If ``self`` is either ``+infinity`` or ``-infinity``, raise ``OverflowError``.
653+
- If ``self`` is ``NaN``, raise ``ValueError``.
585654
"""
586655

587656
def __invert__(self: array, /) -> array:

Diff for: spec/API_specification/array_object.rst

+1
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ Methods
283283
array.__and__
284284
array.__array_namespace__
285285
array.__bool__
286+
array.__complex__
286287
array.__dlpack__
287288
array.__dlpack_device__
288289
array.__eq__

0 commit comments

Comments
 (0)