Arithmetic right shift 2026-10-24
An arithmetic right shift propagates the sign bit into the vacated high positions. For a signed two's complement integer, its result is division by rounded down. This differs from C integer division on negative nonmultiples of , because that quotient truncates towards zero. Shifting an -bit word arithmetically by produces zero for a nonnegative value and the all-one word, representing , for a negative value.
Binary number Created 2026-10-03 Updated 2026-11-05
A binary representation writes a number in positional notation with radix two and binary digits zero and one. To the left of the binary point the place values are ; to its right they are . For example,
Binary notation changes the numeral, not the underlying number. The same value is in decimal. A finite binary fraction represents a dyadic rational, while an infinite binary expansion can represent any real number in the unit interval. Storing a finite binary string additionally requires an interpretation such as unsigned interpretation or two's complement.
Doubling-loop ceiling logarithm Created 2026-10-25 Updated 2026-11-05
For an input , start at and repeatedly increment and double while . In exact arithmetic, the loop invariant and the minimality of the terminating index give . For a general positive real input, the formula is instead : if , the loop makes no updates and cannot return a negative index.
Finite-width integer arithmetic also requires an overflow check. In wrapping signed 32-bit arithmetic, doubling produces the negative value and a further doubling produces zero. For a positive input exceeding , the loop can then remain at zero indefinitely. This is a two's complement wraparound example, not a universal language rule for signed overflow. A signed 64-bit doubling variable can represent the first power of two above every positive signed 32-bit input, repairing this particular range. The proof of the mathematical loop and the representation limits are separate parts of its correctness argument.
Extract one four-bit digit at a time, beginning at the most significant end of the Java int. A lookup string supplies characters, but no library performs the conversion:
java
static String toHex(int value) {
    String digits = "0123456789abcdef";
    String answer = "";
    boolean started = false;
    for (int shift = 28; shift >= 0; shift -= 4) {
        int digit = (value >>> shift) & 15;
        if (started || digit != 0 || shift == 0) {
            answer = answer + digits.charAt(digit);
            started = true;
        }
    }
    return answer;
}
The logical right bit shift >>> inserts zeros, and the bit mask 15 retains exactly the low four bits of the shifted word. Each emitted character is therefore the corresponding hexadecimal digit. The started flag suppresses leading zero digits; the shift == 0 exception makes zero produce "0", rather than an empty string.
A negative Java integer uses two's complement. Its top bit is set, so the first extracted digit is between eight and fifteen and all eight digits are emitted. We interpret its original 32-bit pattern, without taking an absolute value or negating a potentially unnegatable minimum integer. In particular, toHex(19) returns "13", toHex(-1) returns "ffffffff", and toHex(Integer.MIN_VALUE) returns "80000000". There are exactly eight iterations, so for this fixed word size the time complexity is constant.
Use strength reduction on the disassembled hot instructions. In a fixed-width wrapping integer model,
The first replacement is a single left bit shift. For the second, preserve the original operand in a register, shift a copy left by four and subtract the original:
text
rOriginal = x
rResult = rOriginal << 4
rResult = rResult - rOriginal
This avoids a general multiplication if shifts and subtraction are cheaper on the target processor. The two identities hold for positive and negative two's complement operands when only the low result bits are required.
Because only a binary is available, patch the machine instructions and adjust displaced branches or use a jump to a replacement code block if the new sequence does not fit. Preserve live registers and the calling convention. If later instructions consume overflow or other condition flags, or the original multiplication produces a double-width result or traps on overflow, matching only the low-word arithmetic is insufficient: those effects must be reproduced or the transformation rejected. Finally, measure the modified program; a fast hardware multiply need not be slower than several replacement instructions.
An -bit two's complement word represents the integer
The leading bit has negative weight. Words beginning with zero encode the nonnegative values; words beginning with one encode the negative values. Equivalently, interpret the whole word as unsigned and subtract when its leading bit is one. For example, the four-bit words 0111, 1000, and 1111 encode , , and respectively. The range is asymmetric: the most negative value has no positive counterpart in the same number of bits.
For a nonzero representable magnitude, complementing all bits and adding one obtains its negative modulo . Fixed-width addition can therefore use the same low-order binary numeral system addition circuitry for signed and unsigned operands; interpreting the result as signed requires detecting integer overflow.
A MIPS R-type instruction has the 32-bit instruction encoding
For add $x,$y,$z, the processor register indices are , and , while . The main opcode selects the R-type family and the function field selects addition. The register file reads its two operands from instruction bits 25:21 and 20:16. In the original datapath, RegDst=1 selects bits 15:11 as the destination, ALUSrc=0 selects the second register file output, and ALUFunc=ADD makes the arithmetic logic unit add its inputs. The result returns to wdata; RegWrite=1 writes it to at the active clock edge. The zero output is irrelevant here.[ref]
A MIPS I-type instruction instead has the instruction encoding
For addi $x,$y,n, , , and the low sixteen bits contain the immediate operand. The register file supplies to the first arithmetic logic unit input. Set RegDst=0 to select bits 20:16 for the destination, and ALUSrc=1 to select the extended immediate operand for the second input. The opcode directly requests addition, so ALUFunc=ADD and RegWrite=1. The second register file read is unused. The returned result is written into .
The sign extension circuit retains the low sixteen bits and copies bit 15 into all sixteen new high positions:
Thus sign extension preserves the signed two's complement value: 0x7fff becomes 0x00007fff, whereas 0x8000 becomes 0xffff8000. For both instructions, the architectural result above assumes no signed overflow; the full MIPS architecture specifies an overflow exception, which is outside this simplified datapath.
For the unsigned interpretation of the binary string, the set positions have weights . Thus
In 16-bit two's complement, the most significant bit is set, so subtract from that unsigned interpretation:
For a half-precision floating-point number, split the fields at their actual boundaries rather than the printed groups of four:
The sign is negative, the true exponent is , and the fraction is . It is a normal finite value, so
Use the stipulated MIPS I-type instruction encoding, whose unused field is zero, so register-file output supplies the hardwired zero register. With and subtraction selected, the arithmetic logic unit computes . Its zero flag detects , while bit 31 of is the sign in two's complement. Therefore the required signed test is
Introduce one new control bit , and replace the zero-flag input to the existing branch XOR by
This needs an AND gate, an OR gate and a tap of the sign bit. With , existing branch behavior is unchanged. With and , the existing branch-taken circuit gives , exactly the positive test. Its output still selects between and the usual sign-extended branch target. The complete control row is
Set for each instruction in parts (a)–(c). Registers and data memory remain unchanged. The available signed slt operation could support a different design; the sign-and-zero design above avoids adding an ALU-input swap and explicitly distinguishes zero from positive values.
Use the AAPCS32 convention: r0 holds the input address, r1 the length, and r0 receives the result. The following Thumb instruction set assembly language uses only scratch processor registers, so no callee-saved registers need saving. Assume the array is valid, halfword-aligned, and has nonnegative length; for the mathematical sum assume it fits a signed 32-bit two's complement integer.
.syntax unified
.thumb
.thumb_func
sum16:
    movs r2, #0             @ accumulated sum
    cmp  r1, #0
    ble  .Ldone             @ empty array; also returns 0 if n < 0
.Lloop:
    movs r3, #0             @ Thumb signed load needs a register offset
    ldrsh r3, [r0, r3]      @ signed halfword at a; offset read before r3 changes
    adds r2, r2, r3         @ include this signed value
    adds r0, r0, #2         @ advance by one short, not one byte
    subs r1, r1, #1         @ one fewer element remains
    bne  .Lloop
.Ldone:
    movs r0, r2             @ result register
    bx   lr                 @ leaf routine: lr was not overwritten
After iterations, the loop invariant is that r2 contains the first elements' sum, r0 points to element , and r1 is . The sign extension in ldrsh supplies the correct signed addend. One iteration preserves this loop invariant, and the decreasing remaining length proves algorithm termination. For the seven-element calls, the sum lies between and , so it fits. For longer arrays that overflow, these instructions compute the sum modulo ; that is not a claim about defined signed C programming language overflow behavior. The operand forms are those of the paper's reference sheet.[ref]
Let the stored bits be and let . The sign extension performed by ldrsh keeps output bit equal to for , and sets every output bit to . Thus a nonnegative halfword gets sixteen leading zero bits, while a negative halfword gets sixteen leading one bits.
Its signed 32-bit two's complement value is
The last expression is exactly the original signed 16-bit value. The equality uses the finite geometric series . In particular, simply inserting zero bits would be wrong for a negative halfword: its unsigned interpretation differs from its signed value by .
Write an -bit binary string as , where each and is most significant. Its unsigned interpretation and two's complement interpretation are
Equivalently, . The ranges are through and through , respectively. The same stored bits can therefore denote different integers depending on the chosen interpretation.
Let , let , and let denote the least nonnegative residue. Here is a signed 32-bit two's complement value. The source instructions, annotated with their derived values, are:
rem1024:
    asrs r3, r0, #31    // r3 = -s: all zero bits or all one bits
    lsrs r3, r3, #22    // r3 = b = 1023*s
    adds r0, r0, r3     // r0 = a+b
    lsls r0, r0, #22    // r0 has word value (a+b)*2^22 modulo 2^32
    lsrs r0, r0, #22    // r0 = u = (a+b) modulo 1024, in 0,...,1023
    subs r0, r0, r3     // r0 = u-b
    bx lr              // return u-b
The first instruction is an arithmetic right shift, so it replicates the sign bit. The second is a logical right shift, turning the all-one word into . The paired shifts then extract the low ten bits, as in (c). Their effect is the residue of even if its two's complement interpretation is negative, because divides the word modulus . The adjusted value is representable for every input: positive inputs are unchanged, and negative inputs gain only .
For , , so the return value is the usual nonnegative remainder . For , put as a mathematical integer, and write with . If , then and the return value is zero. If , then
These are precisely the remainders for C integer division, whose quotient truncates towards zero. In every case the result has the dividend's sign or is zero, has magnitude below , and satisfies . The proof includes the smallest representable input: was used only in mathematical reasoning, not as an overflowing machine operation.[ref]
Use the same bias, then an arithmetic right shift by ten:
div1024:
    asrs r3, r0, #31    // -1 when a<0, otherwise 0
    lsrs r3, r3, #22    // b = 1023 when a<0, otherwise 0
    adds r0, r0, r3     // a+b, representable for every signed input
    asrs r0, r0, #10    // floor((a+b)/1024)
    bx lr
An arithmetic right shift of a two's complement integer computes division rounded down. For , this already equals truncation towards zero. For , the signed power-of-two division by biasing identity is
Indeed, writing with makes the adjusted numerator ; its quotient rounded down is for every , including zero. Thus the code returns the signed quotient in all cases and contains no data-dependent branch. The final bx lr simply returns to the caller.
Radix sort key encoding 2026-10-18
An encoding for radix sort must make the intended total order of sort keys agree with the lexicographic order of its fixed-width numerical digit tuples. The positional notation for bounded nonnegative integers has this property. At the most significant differing position , a one-unit numerical digit difference contributes , while all lower positions together contribute at most
This geometric series shows why lower numerical digits cannot reverse that comparison. Leading zero padding works here because it preserves place values and the represented integer.
For signed integers in a known integer interval , encode and choose with . This order-preserving function is also injective: exactly when . For , the four-bit encodings of are after adding eight. Restore the original signed sort keys when displaying the complete sorting records; the encoding need not replace their data. Sorting the unsigned values of raw two's complement bit patterns would put nonnegative integers before negative ones, so their representation alone is not this ordered encoding.
For variable-length strings, first specify the alphabet order and whether a proper prefix precedes its extensions. As an original construction, use , let every string have length at most three, encode as one and as two, and append zeros to width three. Zero is reserved for an end marker strictly below every real symbol. The strings encode as in radix three, which preserves their lexicographic order. A differing real symbol decides the comparison; at a prefix boundary, the shorter string's zero comes before the extension's one or two. Left padding would instead encode as and as , reversing . Padding raw bytes with zero also fails if zero is an allowed data symbol: distinct strings can then receive the same encoding. A reserved end marker and an explicit symbol ordering are essential; byte order alone does not establish a desired human text order.
Figure 1.
Stable ties preserve lower digits; suitable encodings preserve the intended order
. Original counterexample above: reversing a tens tie destroys the units order and a later stable hundreds pass cannot repair it. Below: signed integer offsets and a reserved end marker for bounded strings produce increasing fixed-width encodings. All entries are exact constructed examples. Details.
For signed two's complement integers, a conditional positive bias converts the rounding behaviour of an arithmetic right shift into C integer division. It can be formed without a conditional branch by turning the sign bit into either zero or a low--bit bit mask.
Proof. Nonnegative needs no adjustment. If , write , . Then , whose quotient rounded down is , exactly the quotient truncated towards zero. The bias fits safely for in an -bit signed word: it is added only to negative inputs, and the largest possible adjusted input is . The corresponding remainder is , where .
Sign extension 2026-10-24
To widen an -bit two's complement integer to bits, preserve the original low bits and fill the new high positions with the old sign bit . The change in signed positional weights is , so the represented signed value is unchanged. Zero extension instead preserves the unsigned interpretation, and changes the signed value of negative inputs.
For an -bit binary string , the unsigned interpretation assigns positive positional weights to its bits. Its values range from zero to . The same stored bits have two's complement value , so interpreting a machine word is a separate choice from storing its bits.