Interesting list Validity (True/False)

Gabriel Genellina gagsl-py2 at yahoo.com.ar
Wed May 16 05:12:32 EDT 2007


En Wed, 16 May 2007 03:16:59 -0300, mensanator at aol.com  
<mensanator 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". See http://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!).

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.

-- 
Gabriel Genellina




More information about the Python-list mailing list