[Python-ideas] Negative hexes

Nick Coghlan ncoghlan at gmail.com
Sun Dec 4 05:57:32 CET 2011

On Sun, Dec 4, 2011 at 12:14 PM, MRAB <python at mrabarnett.plus.com> wrote:
> On 04/12/2011 02:06, Nick Coghlan wrote:
>> ".4d" would still raise an exception, though - I don't know of any
>> obvious way to make two's complement notation meaningful in base 10.
> It wouldn't be two's complement in that case, it would be ten's
> complement. (Ever used BCD arithmetic in assembly language? :-))
> Actually, would it really be two's complement in octal or hexadecimal
> either? Wouldn't it be eight's complement and sixteen's complement
> respectively?

For hexadecimal, it doesn't make much difference, since the number of
bits per digit is a power of 2: 2**32 == (2**4)**8

For octal, you're right, since it would be 2**33 == (2**3)**11

I quite like Terry's definition, which does extend cleanly to 'd' (as
well as giving the expected answer for 'b', 'o', 'x' and 'X'):

For integers, the precision field would be used to specify the
expected maximum number of digits in the answer, and to switch the
representation of negative values to the appropriate 'complement' form
(e.g. two's complement for binary numbers).

When a precision ".prec" is specified for an integer formatting code
(b, o, d, x or X), the value to be displayed would be calculated as

    _BASES = dict(b=2,o=8,d=10,x=16,X=16)
    _base = _BASES[format_code]
    _prec_bound = _base ** prec
    _max_value = _prec_bound / 2
    if value < -_max_value or value >= _max_value:
        _code = _BASE_NAMES[format_code]
        raise ValueError("Integer {} too large for {} precision of
{}".format(value, _code, n))
    _value = _prec_bound - value

However, I'm not sure that qualifies as *useful* behaviour - while the
bounds checking aspect could be useful for decimal, the complement
form of negative numbers is almost never going to be what anyone
wants. If we decide to improve things in terms of Python-level
handling of two's complement arithmetic, perhaps it would make more
sense to just provide a method on int objects that calculates the
two's complement of a number for a given bit length? Something like:

def as_twos_complement(self, bits):
    if self.bit_length() >= bits:
         raise ValueError("int {} too large for {}-bit signed
precision".format(self, bits))
    if self >= 0:
         return self
    return 2**bits + self # self is known to be negative at this point

As for whether this is worth doing or not... I think so. While Python
integers may be limited in size solely by available memory, it's going
to be a fact of computing life for quite some time that there are
going to be fixed size signed and unsigned integers under the hood
*somewhere*. We already provide a mechanism to find out how many bits
a given integer needs, this would be about providing a standard,
efficient, mechanism to convert negative integers to their two's
complement positive equivalents for a given number of bits.


Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia

More information about the Python-ideas mailing list