Skip to content

BUG: Inconsistent behaviour of return type of int64.__pow__ #8809

Closed

Description

@eric-wieser

Raised by this stackoverflow question. The following code , run on master...

x_actual = 49997
x3_actual = x_actual ** 3

for dtype in [np.int64, np.uint64, np.float64]:
	x = {}
	x['scalar'] = dtype(x_actual)
	x[    '0d'] = np.array(x_actual, dtype=dtype)
	x[    '1d'] = np.array([x_actual], dtype=dtype)
	x[    '2d'] = np.array([[x_actual]], dtype=dtype)

	x3 = {k: x**3 for k, x in x.items()}

	assert all(v == x3_actual for v in x3.values())  #ok

	print("input type of {}:".format(np.dtype(dtype)))
	for k, v in x3.items():
		print("{:>8s}: {}".format(k, v.dtype))
	print()

Gives the alarming output of:

input of int64
  scalar: int64
      0d: int64
      1d: int64
      2d: int64

input of uint64
  scalar: float64
      0d: float64
      1d: uint64    # What?
      2d: uint64    # What?

input of float64
  scalar: float64
      0d: float64
      1d: float64
      2d: float64

The return dtype of power should not depend on the shape of the input array

Activity

  1. changed the title [-]BUG: Inconsistent behaviour of return type of uint64.__pow__[/-] [+]BUG: Inconsistent behaviour of return type of __pow__[/+] on Mar 22, 2017
  2. changed the title [-]BUG: Inconsistent behaviour of return type of __pow__[/-] [+]BUG: Inconsistent behaviour of return type of int64.__pow__[/+] on Mar 22, 2017
  3. ahaldane commented on May 8, 2017

    @ahaldane
    Member

    Isn't this a problem with all ufuncs?

    Extending your example a little, and testing for multiplication a*b:

    val = 1
    cases = [(' p', val)]
    for dtype,name in zip([np.int64, np.uint64], ['i', 'u']):
        cases.extend([('s' + name, dtype(val)),
                      ('0' + name, np.array(val, dtype=dtype)),
                      ('1' + name, np.array([val], dtype=dtype)),
                      ('2' + name, np.array([[val]], dtype=dtype))])
    names, tps = zip(*cases)
    ret = [[(a*b) for n,b in cases] for n1,a in cases]
    kinds = [['p' if type(k) == int else k.dtype.kind for k in r] for r in ret]
    print "     " + " ".join(names)
    print "\n".join(n + "    " + "  ".join(d) for n,d in zip(names, kinds))

    Output: (p = python, i = int, u = uint, s = scalar, 0,1,2 = 0d,1d,2d)

          p si 0i 1i 2i su 0u 1u 2u
     p    p  i  i  i  i  f  f  u  u
    si    i  i  i  i  i  f  f  u  u
    0i    i  i  i  i  i  f  f  u  u
    1i    i  i  i  i  i  i  i  f  f
    2i    i  i  i  i  i  i  i  f  f
    su    f  f  f  i  i  u  u  u  u
    0u    f  f  f  i  i  u  u  u  u
    1u    u  u  u  f  f  u  u  u  u
    2u    u  u  u  f  f  u  u  u  u
    

    the power operation gives the same table.

  4. ahaldane commented on May 8, 2017

    @ahaldane
    Member

    Also, this is loosely related to #8231 and the related discussions on the mailing list last year about integer powers:

    First in June under subject "Integers to integer powers, let's make a decision ", then in October under the same thread plus others like "fpower".

    (but to be clear, this is a somewhat different issue)

  5. eric-wieser commented on Jan 4, 2018

    @eric-wieser
    MemberAuthor

    The shape inconsistencies is #10322 again

  6. FrozenBob commented on Nov 16, 2020

    @FrozenBob

    This is the result of NumPy's "type demotion" rules for mixed scalar/array operations. When a positive-dimensional array and a 0-dimensional array or array scalar participate in a binary operation, the scalar gets "type demoted" based on its value, so 3 gets demoted to uint8, and the result dtype is uint64. On the other hand, when both operands are scalar, NumPy treats 3 as having dtype np.int_, which is signed, and numpy can't find an integer dtype big enough to hold all values of uint64 and int_, so it uses float64.

    This is documented in the docs for numpy.result_type. (The implementation is in convert_datatype.c.)

    The Stack Overflow question also showed what looked like NumPy using a floating-point power implementation for the uint64 output case. I don't know why that was happening, but it seems to have been fixed at some point after the question was asked.

  7. seberg commented on Nov 19, 2022

    @seberg
    Member

    Closing as duplicate of gh-22624

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions