FutureWarning

Bengt Richter bokr at oz.net
Mon Dec 27 23:31:01 EST 2004


On Fri, 24 Dec 2004 10:10:38 -0500, Peter Hansen <peter at engcorp.com> wrote:

>Egor Bolonev wrote:
>> =================
>> C:\Documents and Settings\ŠÕÀ³\My  
>> Documents\Scripts\octopus_eye\1\oct_eye_db.py:
>> 213: FutureWarning: hex()/oct() of negative int will return a signed  
>> string in P
>> ython 2.4 and up
>>   if hex(binascii.crc32(data))[0] == '-':
>> =================
>> hex() will return numbers like -0xa1?
>
>Python 2.4 is out already, so it's easy to check:
>
>c:\>python
>Python 2.4 (#60, Nov 30 2004, 11:49:19) [MSC v.1310 32 bit (Intel)] on win32
>Type "help", "copyright", "credits" or "license" for more information.
> >>> hex(-55)
>'-0x37'
>
Something has been lost in going to this format, namely the convenient use
of 'hex' to represent the abstract bit pattern of a two's complement representation of
a signed integer.  The only question is how important this will turn out to be.
There is no problem generating any of several unambigous representations, but there
is a problem deciding which might be the best, e.g. if we want to add a new format
to the ones in
   http://docs.python.org/lib/typesseq-strings.html


This bugs me, so I'll say it again:

    http://mail.python.org/pipermail/python-list/2003-August/178830.html

The hex problem is a base-16 analogue to representing negative numbers in complement
form in any other base (though even bases provide special possibilities). E.g., for
base B we can just ensure that the leading digit is either 0 or B-1, i.e., for base 10
that would be 0 or 9:
    0 => 0
    1 => 01
   -1 => 9
   -2 => 98

Not very tested:

 >>> def basecompl(x, B=10, digits='0123456789abcdefghijklmnopqrstuvwxyz'):
 ...     if not x: return digits[0]
 ...     s = []
 ...     while x and x != -1:
 ...         x, r = divmod(x, B)
 ...         s.append(digits[r])
 ...     if not s or s[-1] not in (digits[0], digits[B-1]):
 ...         s.append(digits[x<0 and B-1 or 0])
 ...     return ''.join(s[::-1])
 ...
 >>> basecompl(0)
 '0'
 >>> basecompl(1)
 '01'
 >>> basecompl(-1)
 '9'
 >>> basecompl(-2)
 '98'
 >>> basecompl(0, 16)
 '0'
 >>> basecompl(1, 16)
 '01'
 >>> basecompl(-1, 16)
 'f'
 >>> basecompl(-2, 16)
 'fe'
 >>> basecompl(0, 8)
 '0'
 >>> basecompl(1, 8)
 '01'
 >>> basecompl(-1, 8)
 '7'
 >>> basecompl(-2, 8)
 '76'
    
Left-padding by repeating the leftmost digit does not change the value,
if you decode it consistently, I think:

 >>> def bcdecode(s, B=10, digits='0123456789abcdefghijklmnopqrstuvwxyz'):
 ...     if s == digits[0]: return 0
 ...     acc = s[0].lower() == digits[B-1] and -B**len(s) or 0
 ...     for i, c in enumerate(s[::-1]):
 ...         acc += digits.index(c)*B**i
 ...     return acc
 ...
 >>> bcdecode('0')
 0
 >>> bcdecode('7', 8)
 -1
 >>> bcdecode('777', 8)
 -1
 >>> bcdecode('999', 10)
 -1
 >>> bcdecode('99', 10)
 -1
 >>> bcdecode('099', 10)
 99
 >>> bcdecode('98')
 -2
 >>> bcdecode('9')
 -1

 >>> bcdecode('01001', 2)
 9
 >>> bcdecode('11111', 2)
 -1
 >>> bcdecode('11110', 2)
 -2
 >>> bcdecode('01111', 2)
 15
 >>> bcdecode('1', 2)
 -1
 >>> bcdecode('11', 2)
 -1
 >>> bcdecode('01', 2)
 1
 >>> bcdecode('0f', 16)
 15
 >>> bcdecode('f', 16)
 -1
 >>> bcdecode('ffff', 16)
 -1
 >>> bcdecode('fffe', 16)
 -2
 >>> bcdecode('fe', 16)
 -2

If you wanted to use these as a new format for integer literals you'd have
to prefix something to indicate how to interpret, like the old 0x prefix, but
not 0x obviously. '0b' for binary would be nice and concise, but maybe something
that could express the base value easily would be good too. Since there's no
upper case '0' or '1' we could use '0Bn:ddddd' -- which would make
int('0B2:10') == int('0B8:76') == int('0B10:98') == int('0B16:fe') == -2

'0b' could be a synonym for '0B2:' and '0h' for '0B16:'

Perhaps there could be string formatting to match, e.g.,

'%<width>.<base>b'  # or B for uppercase.

So
    '%.2b'%3 => '011'
and
    '%04.16B'%-3 => 'FFFD'

and if you wanted to create literals, you would write

    '0b2:%.2b'%3 => '0b2:011'
and
    '0b16:%04.16B'%-3 => '0b16:FFFD'

respectively. Etc., etc.
 

Oops, that
 ...         acc += digits.index(c)*B**i

above should have been

 ...         acc += digits.index(c.lower())*B**i

It's obviously not optimized, and there may be bugs, but this should at least
communicate the idea (a little modified from Aug 2003 ideas ;-)

Regards,
Bengt Richter



More information about the Python-list mailing list