8000 NumPy's implementation of scalar integer ** integer has very weird casting · Issue #7449 · numpy/numpy · GitHub
[go: up one dir, main page]

Skip to content
NumPy's implementation of scalar integer ** integer has very weird casting #7449
Open
@njsmith

Description

@njsmith

Apropos #7447 (CC @ewmoore @charris):

I was curious about what was going on here, and it looks much uglier than we realized :-(

Little test script that tries doing 4 ** -4 using different types:

Old testing script (and results)
signed_int_types = [np.int8, np.int16, np.int32, np.int64, int]
all_int_types = signed_int_types + [np.uint8, np.uint16, np.uint32, np.uint64]
for base_type in all_int_types:
    for exponent_type in signed_int_types:
        result = base_type(4) ** exponent_type(-4)
        print("{} ** {} -> {} ({})".format(base_type.__name__,
                                           exponent_type.__name__,
                                           result.__class__.__name__,
                                           result))

On current master (after #7447 is merged):

int8 ** int8 -> float32 (0.00390625)
int8 ** int16 -> int16 (0)
int8 ** int32 -> int32 (0)
int8 ** int64 -> int64 (0)
int8 ** int -> int64 (0)
int16 ** int8 -> float32 (0.00390625)
int16 ** int16 -> float32 (0.00390625)
int16 ** int32 -> int32 (0)
int16 ** int64 -> int64 (0)
int16 ** int -> int64 (0)
int32 ** int8 -> float64 (0.00390625)
int32 ** int16 -> float64 (0.00390625)
int32 ** int32 -> float64 (0.00390625)
int32 ** int64 -> int64 (0)
int32 ** int -> int64 (0)
int64 ** int8 -> float64 (0.00390625)
int64 ** int16 -> float64 (0.00390625)
int64 ** int32 -> float64 (0.00390625)
int64 ** int64 -> float64 (0.00390625)
int64 ** int -> float64 (0.00390625)
int ** int8 -> int64 (0)
int ** int16 -> int64 (0)
int ** int32 -> int64 (0)
int ** int64 -> float64 (0.00390625)
int ** int -> float (0.00390625)
uint8 ** int8 -> int16 (0)
uint8 ** int16 -> int16 (0)
uint8 ** int32 -> int32 (0)
uint8 ** int64 -> int64 (0)
uint8 ** int -> int64 (0)
uint16 ** int8 -> int32 (0)
uint16 ** int16 -> int32 (0)
uint16 ** int32 -> int32 (0)
uint16 ** int64 -> int64 (0)
uint16 ** int -> int64 (0)
uint32 ** int8 -> int64 (0)
uint32 ** int16 -> int64 (0)
uint32 ** int32 -> int64 (0)
uint32 ** int64 -> int64 (0)
uint32 ** int -> int64 (0)
uint64 ** int8 -> float64 (0.00390625)
uint64 ** int16 -> float64 (0.00390625)
uint64 ** int32 -> float64 (0.00390625)
uint64 ** int64 -> float64 (0.00390625)
uint64 ** int -> float64 (0.00390625)

This is all extremely extremely weird and inconsistent...


Summary/edit by @seberg 2019-05-23:

On current master (and 1.16) we now error for many of these cases as found using the modified snippet:

signed_int_types = [np.int8, np.int16, np.int32, np.int64, int]
all_int_types = signed_int_types + [np.uint8, np.uint16, np.uint32, np.uint64]
for base_type in all_int_types:
    for exponent_type in signed_int_types:
        try:
            result = base_type(4) ** exponent_type(-4)
        except Exception as e:
            result = e
        print("{} ** {} -> {} ({})".format(base_type.__name__,
                                           exponent_type.__name__,
                                           result.__class__.__name__,
                                           result))

Giving (again 1.16, master shortly before 1.17):

int8 ** int8 -> ValueError (Integers to negative integer powers are not allowed.)
int8 ** int16 -> ValueError (Integers to negative integer powers are not allowed.)
int8 ** int32 -> ValueError (Integers to negative integer powers are not allowed.)
int8 ** int64 -> ValueError (Integers to negative integer powers are not allowed.)
int8 ** int -> ValueError (Integers to negative integer powers are not allowed.)
int16 ** int8 -> ValueError (Integers to negative integer powers are not allowed.)
int16 ** int16 -> ValueError (Integers to negative integer powers are not allowed.)
int16 ** int32 -> ValueError (Integers to negative integer powers are not allowed.)
int16 ** int64 -> ValueError (Integers to negative integer powers are not allowed.)
int16 ** int -> ValueError (Integers to negative integer powers are not allowed.)
int32 ** int8 -> ValueError (Integers to negative integer powers are not allowed.)
int32 ** int16 -> ValueError (Integers to negative integer powers are not allowed.)
int32 ** int32 -> ValueError (Integers to negative integer powers are not allowed.)
int32 ** int64 -> ValueError (Integers to negative integer powers are not allowed.)
int32 ** int -> ValueError (Integers to negative integer powers are not allowed.)
int64 ** int8 -> ValueError (Integers to negative integer powers are not allowed.)
int64 ** int16 -> ValueError (Integers to negative integer powers are not allowed.)
int64 ** int32 -> ValueError (Integers to negative integer powers are not allowed.)
int64 ** int64 -> ValueError (Integers to negative integer powers are not allowed.)
int64 ** int -> ValueError (Integers to negative integer powers are not allowed.)
int ** int8 -> ValueError (Integers to negative integer powers are not allowed.)
int ** int16 -> ValueError (Integers to negative integer powers are not allowed.)
int ** int32 -> ValueError (Integers to negative integer powers are not allowed.)
int ** int64 -> ValueError (Integers to negative integer powers are not allowed.)
int ** int -> float (0.00390625)
uint8 ** int8 -> ValueError (Integers to negative integer powers are not allowed.)
uint8 ** int16 -> ValueError (Integers to negative integer powers are not allowed.)
uint8 ** int32 -> ValueError (Integers to negative integer powers are not allowed.)
uint8 ** int64 -> ValueError (Integers to negative integer powers are not allowed.)
uint8 ** int -> ValueError (Integers to negative integer powers are not allowed.)
uint16 ** int8 -> ValueError (Integers to negative integer powers are not allowed.)
uint16 ** int16 -> ValueError (Integers to negative integer powers are not allowed.)
uint16 ** int32 -> ValueError (Integers to negative integer powers are not allowed.)
uint16 ** int64 -> ValueError (Integers to negative integer powers are not allowed.)
uint16 ** int -> ValueError (Integers to negative integer powers are not allowed.)
uint32 ** int8 -> ValueError (Integers to negative integer powers are not allowed.)
uint32 ** int16 -> ValueError (Integers to negative integer powers are not allowed.)
uint32 ** int32 -> ValueError (Integers to negative integer powers are not allowed.)
uint32 ** int64 -> ValueError (Integers to negative integer powers are not allowed.)
uint32 ** int -> ValueError (Integers to negative integer powers are not allowed.)
uint64 ** int8 -> float64 (0.00390625)
uint64 ** int16 -> float64 (0.00390625)
uint64 ** int32 -> float64 (0.00390625)
uint64 ** int64 -> float64 (0.00390625)
uint64 ** int -> float64 (0.00390625)

So the integer+integer which use float as a common type are a bit strange in this sense.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0