Interesting list Validity (True/False)

mensanator at aol.com mensanator at aol.com
Wed May 16 13:26:33 EDT 2007


On May 16, 4:12 am, "Gabriel Genellina" <gagsl-... at yahoo.com.ar>
wrote:
> En Wed, 16 May 2007 03:16:59 -0300, mensana... at aol.com  
> <mensana... at aol.com> escribió:
>
>
>
>
>
> > On May 15, 7:07 pm, "Gabriel Genellina" <gagsl-... at yahoo.com.ar>
> > wrote:
> >> >>>> import gmpy
> >> >>>> a = 2**177149-1
> >> >>>> b = gmpy.mpz(2**177149-1)
> >> >>>> a==b
> >> > True
> >> >>>> print '%d' % (b)
>
> >> > Traceback (most recent call last):
> >> >   File "<pyshell#4>", line 1, in <module>
> >> >     print '%d' % (b)
> >> > TypeError: int argument required
>
> >> > So although the comparison operator is smart enough to realize
> >> > the equivalency of numeric types and do the type conversion,
> >> > the print statement isn't so smart.
>
> >> This is up to the gmpy designers/writers/maintainers. Anyone writing a
> >> class chooses which features to implement, which ones to omit, how to
> >> implement them, etc. The code may contain bugs, may not be efficient,  
> >> may
> >> not behave exactly as the users expect, may not have anticipated all  
> >> usage
> >> scenarios, a long etc. In this case, probably the gmpy writers have  
> >> chosen
> >> not to allow to convert to int, and they may have good reasons to not do
> >> that (I don't know what platform are you working in, but I feel that  
> >> your
> >> b object is somewhat larger than sys.maxint...).
>
> > Then how does this work?
>
> >>>> print '%d' % (long(gmpy.mpz(2**177149-1)))
> > 1454...<53320 digits snipped>...3311
>
> > I honestly don't understand why there's a problem here.
> > If print can handle arbitrary precision longs without
> > a problem, why does it fail on mpzs > sys.maxint?
> > If the gmpy writers are not allowing the conversion,
> > then why do small mpz values work? Something smells
> > inconsistent here.
>
> Python (builtin) "integral numbers" come on two flavors: int and long.  
> ints correspond to the C `long` type usually, and have a limited range, at  
> least from -2**31 to 2**31-1; most operations have hardware support (or at  
> least it's up to the C compiler). Long integers are a totally different  
> type, they have unlimited range but are a lot slower, and all operations  
> must be done "by hand". Seehttp://docs.python.org/ref/types.html
>
> If you say "%d" % something, Python first tries to see if `something` is a  
> long integer -not to *convert* it to a long integer, just to see if the  
> object *is* a long integer. If it's a long, it's formatted accordingly.
> If not, Python sees if `something` is a plain integer. If not, it sees if  
> it's a number (in this context, that means that the structure describing  
> its type contains a non-NULL tp_as_number member) and tries to *convert*  
> it to an integer. Notice that if the object whas not originally a long  
> integer, no attempt is made to convert it to a long using the nb_long  
> member - just a plain integer conversion is attempted.
> It's at this stage that a large mpz object may fail - when its value can't  
> fit in a plain integer, it raises an OverflowError and the "%d" formatting  
> fails.
> If you force a conversion to long integer, using long(mpz(...)) as above,  
> the % operator sees a long integer from start and it can be formatted  
> without problems.
>
> I don't know if this asymmetric behavior is a design decision, a historic  
> relic, a change in protocol (is nb_int allowed now to return a  
> PyLongObject, but not before?), a "nobody cares" issue, or just a bug.  
> Perhaps someone else can give an opinion - and certainly I may be wrong, I  
> had never looked at the PyString_Format function internal details before  
> (thanks for providing an excuse!).

Ah, thanks for the info, I know nothing about Python internals.

That implies that although this works:

>>> print '%d' %(1234567890.0)
1234567890

this does not:

>>> print '%d' %(12345678901234567890.0)

Traceback (most recent call last):
  File "<pyshell#1>", line 1, in <module>
    print '%d' %(12345678901234567890.0)
TypeError: int argument required

So we can work around it by doing the long conversion
ourselves since print only knows how to invoke int conversion.

>>> print '%d' %(long(12345678901234567890.0))
12345678901234567168

which demonstartes the problem is not with gmpy.

>
> As a workaround you can always write "%d" % long(mpznumber) when you want  
> to print them (or perhaps "%s" % mpznumber, which might be faster).
>
> > How is it that
>
> >>>> print '%d' % (1.0)
> > 1
>
> > doesn't make a type mismatch? Obviously, the float
> > got changed to an int and this had nothing to do with
> > gmpy. Is it the print process responsible for doing
> > the conversion? Maybe I should say invoking the
> > conversion? Maybe the gmpy call tries to literally
> > convert to an integer rather than sneakily substitute
> > a long?
>
> Same as above: is the argument a long integer? no. is it a number? yes.  
> Convert to int. No errors? Apply format.

Thanks again, as long as I know why the behaviour is strange,
I know how to work around it

>
> --
> Gabriel Genellina




More information about the Python-list mailing list