longinteger on Cray J90

Tim Peters tim_one at email.msn.com
Tue May 23 03:02:43 EDT 2000


[posted & mailed]

[Marc Poinot]
> I'm trying to use Python on a J90.

Poor Marc!

> This Cray, and its folks, has 8 bytes
> size shorts, int, long, long long, etc...
> Looks like some hardware discount ;) ?
>
> I have a 8 bytes concern with longobject.c
> which manipulates heavily bit masks.
>
> I found that the carry (add) and borrow (sub)
> are not "masked" correctly as shorts.

I don't know what this means, alas, but since you're likely the only person
on c.l.py with access to a J90, you're going to have to work hard to be
clear.

> Thus, it looks like some of the asserts are
> not relevants (i.e. assert(borrow == 0) ),
> but not only the asserts.

The asserts are certainly relevant.  If the asserts are triggering,
something is wrong with the code.

> As soon as your long object is larger than SHIFT,
> at least the borrow/carry is not "cleared" correctly.
>
> Python 1.5.2 (#16, May 22 2000, 12:14:02) [C] on unicos10
> Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
> >>> a=01000000000000000

Is there some reason this is in octal?  And/or some reason 2**45 is
especially interesting?

> >>> a-1
> 35184372088831
> >>> b=long(a)
> >>> b
> 35184372088832L
> >>> b-1
> Assertion failed: borrow == 0, file longobject.c, line 1120
> Abort(coredump)

Well, *that's* not good <wink>.

> I've read some emails from Konrad H. and Tim P.
> about that. K.Hinsen has problems with regexp.
> T.Peters suggested the use of a macro
> to mask the shorts.

That was different:  the old regex code (which Guido didn't write) assumed
that sizeof(short) == 2 exactly, and that's a bad assumption.  Python's
longint code *intended* to assume only that

1. sizeof(unsigned short) >= 2

2. sizeof(unsigned long) >= 4

There is *no* intended assumption that sizeof(unsigned long) >=
2*sizeof(unsigned short), or any of the other bad assumptions you're
thinking of.  So, given that this code doesn't work for you, there are two
likely possibilities:

A. The compiler is generating bad code.  Did you try compiling Python
   *without* optimization?  If not, try that.

B. It's a shallow bug in a line or two of longobject.c, easy to track down
   if you run under a debugger on a machine where it fails, but could be
   impossible to track down via email without access to a failing platform.

> But such a use seems difficult as the long object representation
> has a digit typedef, I have to find back the use of this type in the
> whole Python code... (I am wrong, K.P. ?).

The "digit" typedef is used only in longintrepr.h and longobject.c.  If you
stop being paralyzed long enough to look at them <wink>, you'll find that
almost all uses are already *obviously* properly masked; e.g.,

			v->ob_digit[i] = (digit) (t & MASK);

> The description in Include/longinterp.h gives some
> details about what the short/digit/wdigit types should
> be able to do. But in my case, I wonder how to make
> a wdigit able to handle twice the size of a digit?

That's not the assumption the code makes.  A twodigit thing needs to be able
to hold an int no bigger than MASK << SHIFT, and MASK is just BASE-1, and
BASE is just 1<<SHIFT, and SHIFT is just 15:  your twodigit is already wide
enough.  You didn't happen to change the SHIFT #define in the code to
something larger than 15?  If you did, that's why it's blowing up.

Ponder ... I think I see a problem here (in x_sub):

	for (i = 0; i < size_b; ++i) {
		/* The following assumes unsigned arithmetic
		   works module 2**N for some N>SHIFT. */
		borrow = a->ob_digit[i] - b->ob_digit[i] - borrow;
		z->ob_digit[i] = borrow & MASK;
		borrow >>= SHIFT;
		borrow &= 1; /* Keep only one sign bit */
	}
	for (; i < size_a; ++i) {
		borrow = a->ob_digit[i] - borrow;
		z->ob_digit[i] = borrow & MASK;
		borrow >>= SHIFT;
	}
	assert(borrow == 0);

Note that the second "for" loop does not have the

		borrow &= 1; /* Keep only one sign bit */

line that's at the bottom of the first "for" loop.  Try copying that line
into the bottom of the second "for" loop too:

	for (; i < size_a; ++i) {
		borrow = a->ob_digit[i] - borrow;
		z->ob_digit[i] = borrow & MASK;
		borrow >>= SHIFT;
		borrow &= 1; /* Keep only one sign bit */  ADD THIS LINE ******
	}

Without that, if the first line ever computes a negative value, "borrow" at
the bottom on your machine will retain 64-15 = 49 copies of the sign bit.
On machines where sizeof(short) == 2, it retains just 16-15=1 sign bit.
Fixing that may well be all there is to this -- but I can't test it for you.

the-line-that's-broken-is-always-the-line-closest-to-the-assert<wink>-ly
    y'rs  - tim







More information about the Python-list mailing list