Skip to content

BUG: Don't use longlong for PyLong if it isn't larger than long - #5890

Closed
jaimefrio wants to merge 1 commit into
numpy:masterfrom
jaimefrio:pylong_as_long
Closed

jaimefrio wants to merge 1 commit into
numpy:masterfrom
jaimefrio:pylong_as_long

Conversation

@jaimefrio

Copy link
Copy Markdown
Member

Closes #5801.

PyLong types are only converted to npy_longlong if it is larger
than npy_long.

Closes numpy#5801.

PyLong types are only converted to npy_longlong if it is larger
than npy_long.
@njsmith

njsmith commented May 18, 2015

Copy link
Copy Markdown
Member

I don't really object to the patch, but this kinda seems like a lot of code to produce exactly equivalent results (all the checks are of the form "if a and b are different, use a, otherwise if they're identical, use b", right?). To me it looks like in #5801 the real underlying bug is that we have two different types that pretend to be identical but aren't quite. Would it make more sense to fix things at that level?

@jaimefrio

Copy link
Copy Markdown
Member Author

I tried the shortcut of, right after the declaration of the NPY_TYPES enum, do something like:

#if NPY_SIZEOF_LONG == NPY_SIZEOF_LONGLONG
#   define NPY_LONGLONG NPY_LONG
#   define NPY_ULONGLONG NPY_ULONG
#endif

but it breaks a gazillion switch statements that have cases for all the types.

I'm afraid that it is too deeply ingrained in the code that byte, short, int, long and long long are all different, even when they are not, to make it easy to get rid of the repeated one.

@njsmith

njsmith commented May 18, 2015

Copy link
Copy Markdown
Member

Yeah, that would also break abi. But what about, say, teaching dtype.eq
that these are the same?
On May 18, 2015 12:10 AM, "Jaime" [email protected] wrote:

I tried the shortcut of, right after the declaration of the NPY_TYPES
enum, do something like:

#if NPY_SIZEOF_LONG == NPY_SIZEOF_LONGLONG

define NPY_LONGLONG NPY_LONG

define NPY_ULONGLONG NPY_ULONG

#endif

but it breaks a gazillion switch statements that have cases for all the
types.

I'm afraid that it is too deeply ingrained in the code that byte, short,
int, long and long long are all different, even when they are not, to
make it easy to get rid of the repeated one.

—
Reply to this email directly or view it on GitHub
#5890 (comment).

@jaimefrio

Copy link
Copy Markdown
Member Author

I have taken a second look into this, and it really seems there is no way out of not using long long when a smaller type will do:

  • Comparison of dtypes does the right thing already:
>>> dt1 = np.dtype(np.int64)
>>> dt2 = np.dtype(np.longlong)
>>> dt1.num == dt2.num  # They are different types...
False
>>> dt1 == dt2  # ...but they compare equal.
True
  • Inheritance is also properly set up, as both types inherit from the same base types:
>>> np.int64.__bases__
(numpy.signedinteger, int)
>>> np.longlong.__bases__
(numpy.signedinteger, int)

This is not enough to stop this:

>>> isinstance(dt2, np.int64)
False

from returning a correct, yet awfully confusing result. Especially given that:

>>> np.longlong.__name__
'int64'

So really the only valid solution is making sure that we always issue the smallest numbered type that fits the requested size, which is what this PR attempts to do.

@njsmith

njsmith commented May 29, 2015

Copy link
Copy Markdown
Member

Sorry to be annoying but... we need to continue to recognize both NPY_LONG and NPY_LONGLONG typenums for ABI compat, but do is there any reason we couldn't have np.int64 is np.longlong? (Aside from the general lovecraftian nature of arraytypes.c.src.)

@charris

charris commented May 30, 2015

Copy link
Copy Markdown
Member

@njsmith np.longlong refers to the C type, so changing that can cause problems. I'd be happy to remove the C long long altogether from our stuff, except where needed for the CPython ABI, but that could still lead to compatibility problems.

@njsmith

njsmith commented May 30, 2015

Copy link
Copy Markdown
Member

In my suggestion np.longlong would still refer to the c long long type, so
I don't understand. It just would use the same object to do so as was also
used to refer to the int64 typedef.
On May 30, 2015 3:39 PM, "Charles Harris" [email protected] wrote:

@njsmith https://github.com/njsmith np.longlong refers to the C type,
so changing that can cause problems. I'd be happy to remove the C long long
altogether from our stuff, except where needed for the CPython ABI, but
that could still lead to compatibility problems.

—
Reply to this email directly or view it on GitHub
#5890 (comment).

@jaimefrio

Copy link
Copy Markdown
Member Author

The problem is that, in most systems, we have two internal types competing for the numpy.int64 label. One is PyLongArrayType_Type, the other is PyLongLongArrayType_Type, which correspond to the long and long long C types. We can point the numpy.int64 object to either one of them, but if we internally keep using them both, we are going to run into a similar problem elsewhere.

I guess I don't fully understand what the ABI constraints are here, which makes it hard to come up with alternatives.

@charris

charris commented May 31, 2015

Copy link
Copy Markdown
Member

Yeah, NVM, I was thinking np.long. Even so, it is probably not a good idea to fix the width of a C type.

@njsmith

njsmith commented May 31, 2015

Copy link
Copy Markdown
Member

I guess in practice "long long" is probably 64 bits on all platforms we
support... But what I meant was that in builds where long long is 64 bits
then np.longlong it should be the same as np.int64, and on builds where
long long is 32 bits then np.longlong should be the same as np.int32, etc.
We already alter the behavior of the c analogue types based on the actual
build to try and fake this, cf. np.longlong printing as "int64".
On May 30, 2015 6:28 PM, "Charles Harris" [email protected] wrote:

Yeah, NVM, I was thinking np.long. Even so, it is probably not a good
idea to fix the width of a C type.

—
Reply to this email directly or view it on GitHub
#5890 (comment).

@charris

charris commented Sep 9, 2015

Copy link
Copy Markdown
Member

Actually, I'd like to get rid of long except for Python API access. In practice long is either the same as either c long long or c int. What is confusing here is that both c long and clong long arrays report their type as int64 but they are actually different types. Not sure what the best fix is. Note that on my box a np.long array is created as long long.

@charris

charris commented Dec 16, 2020

Copy link
Copy Markdown
Member

Going to close this, PyLong is gone with Python 2.7. The use of C long/long long is still under discussion, but this is not the best place for that.

@charris charris closed this Dec 16, 2020
@eric-wieser

Copy link
Copy Markdown
Member

Looks like all the code in this PR is in removed if branches anyway now.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Elements of int64 array made from converting Python 2.x longs not int64 even though ndarray dtype is int64

5 participants