Skip to content

Shift Right

Level: 201 · for anyone with a hex editor open

One line: X[i] >>= Operand moves each value's bits toward the bottom and drops what falls off, and the question is what comes in at the top — zeros for an unsigned type, and for a signed one whatever the implementation chooses, which C leaves open and the manual does not answer — so this page prints both candidates rather than guessing.

What the dialog does

The manual writes Shift Right as X[i] >>= Operand (Hex Operations). For an unsigned value the rule is settled: zeros come in at the top, and Shift Right n is dividing by 2ⁿ and throwing the remainder away. For a negative signed value, C calls the result implementation-defined. The common choice copies the sign bit in, which keeps a negative value negative — and every compiler this library runs makes it — but a C-notation description is not a promise that this dialog made it too.

In Python

Verified output of shift_right_py.py — regenerated by tools/run_examples.py, never hand-typed.

1. WHAT COMES IN AT THE TOP
------------------------------------------------------------------------
   Shift Right f0 81 7f by 1 and by 4:

     Unsigned Byte                  >> 1  78 40 3f    >> 4  0f 08 07
     Signed Byte, sign copied in    >> 1  f8 c0 3f    >> 4  ff f8 07
     Signed Byte, zeros in          >> 1  78 40 3f    >> 4  0f 08 07

   An Unsigned Byte always takes zeros. For a Signed Byte, C says a
   negative value's >> is implementation-defined; every compiler this
   library runs copies the sign bit, which is the second row, and the
   manual does not say which rule the dialog follows. 7F is positive,
   and all three rows agree on it.

2. SHIFT RIGHT 4 AND AND 0F SPLIT A BYTE INTO ITS HEX DIGITS
------------------------------------------------------------------------
     é               c3 a9
     Shift Right 4   0c 0a   the left digits
     Binary And 0F   03 09   the right digits

3. SHIFT RIGHT 1 IS NOT DIVIDE 2 ON A NEGATIVE VALUE
------------------------------------------------------------------------
   Copying the sign bit rounds toward minus infinity; C's division
   rounds toward zero:

     Signed Bytes where they differ       64 of 256
     every one of them negative and odd   True
     -7 >> 1, and -7 / 2                  -4 and -3

4. SHIFT RIGHT 8 MOVES A SHORT'S HIGH BYTE DOWN
------------------------------------------------------------------------
   0x1234 >> 8 is 0x0012, stored both ways:

     Unsigned Short, big     12 34 -> 00 12
     Unsigned Short, little  34 12 -> 12 00

What comes in at the top

Section 1 shifts F0 81 7F by 1 and by 4 under three rules. As Unsigned Byte, zeros come in: F0 >> 1 is 78. As Signed Byte with the sign copied in, F0 — which is −16 — stays negative: F8, which is −8. As Signed Byte with zeros coming in, the bytes are identical to the unsigned row. 7F is positive, and all three rules agree on it. So the dialog's Signed Byte can match only one of the two signed rows, and the page cannot tell you which; the second item under Try it can.

Shift Right is not Divide on a negative value

Copying the sign bit in rounds toward minus infinity. C's division rounds toward zero. Section 3 counts the Signed Bytes on which Shift Right 1 and Divide 2 disagree: 64, every one negative and odd. −7 shifted right by 1 is −4; −7 divided by 2 is −3. Divide meets the same fact from its side, and it is the reason an optimiser may replace a division by a shift only where the value cannot be negative.

Splitting a byte into hex digits

Section 2 is the everyday use. Shift Right 4 keeps a byte's high nibble and And 0F keeps its low one, so the two together take é's bytes C3 A9 apart into the digits C, A and 3, 9. Section 4 moves a whole byte down a Short instead: 0x1234 >> 8 is 0x0012, which is 00 12 big-endian and 12 00 little-endian.

What the manual does not say

  • Whether a Signed type copies the sign bit in or brings in zeros — the two signed rows of section 1.
  • What a count of the width of the type or more does.

If you are coming from Python or ABAP

Python. Python's >> on a negative number copies the sign — its documentation defines a right shift as floor division by a power of two — so -16 >> 1 is −8 and section 1's second row is Python's own answer. The zeros rule is (v & 0xFF) >> n on the bit pattern.

ABAP. (Not machine-checked — CI cannot run ABAP.) ABAP's bit expressions have no operator that moves a bit ↗, so a right shift of an integer is a division — and the choice of division is the choice of rule. DIV keeps the remainder non-negative ↗, which for a positive power of two rounds a negative value down, so value DIV ipow( base = 2 exp = n ) behaves like the sign-copying row; / rounds commercially and matches neither.

Try it

  1. Shift Right 4 a copy of a text file as Unsigned Byte. Every byte is now its own left hex digit, 00 to 0F.
  2. Type F0 81 7F, set Treat Data As to Signed Byte, and Shift Right 1. Compare the result with section 1 and note which rule the dialog follows.
  3. On two copies of a run of negative Signed Bytes, Shift Right 1 one and Divide 2 the other, then compare them with Tools > Compare.
  4. Type 34 12, Shift Right 8 as Unsigned Short under each Endian setting, and explain each result from the value that was read.

See also

  • Divide — the division that rounds the other way
  • Shift Left — the direction where the sign does not matter
  • Block Shift Right — the same question about the top, for a whole range
  • Modulus — the other half of splitting a byte into digits