[Tutor] operators >> and &
alan.gauld at btinternet.com
Sun Feb 14 10:16:18 CET 2010
"Steven D'Aprano" <steve at pearwood.info> wrote
>> They are not gone however there are still 32 bits in an integer so
>> the top bits *should* be set to zero.
> No, Python ints are not 32 bit native ints. They're not even 64 bit
> ints. Python has unified the old "int" type with "long", so that ints
> automatically grow as needed. This is in Python 3.1:
Valid point but irrelevant to the one I was making which
is that the number after shifting is longer than 8 bits.
>> But glitches can occur from time to time...
> If Python had a glitch of the magnitude of right-shifting non-zero bits
> into a number, that would be not just a bug but a HUGE bug.
Bit shifting is machine specific. Some CPUs (the DEC PDP
range from memory is an example) will add the carry bit for
example, most will not. But you can never be sure unless you
know exactly which artchiotecture the program will run on.
And of course data can always be corrupted at any time so its
always wise to take as many precautions as possibe to keep
it clean (although corruption within the CPU itself is, I agree,
> be as serious as having 1+1 return 374 instead of 2. Guarding against
> (say) 8 >> 1 returning anything other than 4
Not if you have a 4 bit processor and the previous opertation
set the carry flag. In that case returning 12 would be emminently
sensible....and used to be a common assembler trick for
recovering from overflow errors.
> guarding against 8//2 returning something other than 4: if you can't
> trust Python to get simple integer arithmetic right,
But ths is not simple integer arithmetic it is bit m,anippulation.
You can use bit manipulation to fake arithmetic but they are
fundamentally different operations and may not always
produce the same results depending on how the designer
> trust it to do *anything*, and your guard (ANDing it with 255) can't be
> trusted either.
Nothing can be trusted 100% on a computer because, as you
say the guard might itself be corrupted. Itas all about risk management.
But when it comes to bit operations I'd always have at least one
extra level of check, whether it be a mask or a checksum.
> It is certainly good practice if you are dealing with numbers which
> might be more than 24 bits to start with:
Its more than good practice there, its essential.
> But *if* you know the int is no more than 32 bits, then adding in a
> guard to protect against bugs in the >> operator is just wasting CPU
It may not be a bug it may be a design feature.
Now all modern CPUs behave as you would expect but if
you are running on older equipment (or specialised
hardware - but that's more unlikely to have Python onboard!)
you can never be quite sure how bitwise operations will react
at boundary cases. If you know for certainty what the runtime
environment will be then you can afford to take a chance.
In the case in point the & 255 keeps the coding style consistent
and provides an extra measure of protection against unexpected
oddities so I would keep it in there.
> cycles and needlessly complicating the code. The right way to guard
> against "this will never happen" scenarios is with assert:
> assert n.bit_length() <= 32 # or "assert 0 <= n < 2**32"
I would accept the second condition but the mask is much faster.
bit_length doesn't seem to work on any of my Pythons (2.5,2.6 and 3.1)
> This has two additional advantages:
> (1) It clearly signals to the reader what your intention is ("I'm
> absolutely 100% sure than n will not be more than 32 bits, but since
> I'm a fallible human, I'd rather find out about an error in my logic as
> soon as possible").
The assert approach is perfectly valid, but since the mask is
more consistent I'd still prefer to use it in this case.
More information about the Tutor