Recent from talks
Contribute something
Nothing was collected or created yet.
Arithmetic shift
View on Wikipedia

| Language or processor | Left | Right |
|---|---|---|
| ActionScript 3, Java, JavaScript, Python, PHP, Ruby, C, C++,[1]D, C#, Go, Julia, Rust (signed types only)[2], Swift (signed types only)[note 1] |
<< |
>>
|
| Ada | Shift_Left [3] |
Shift_Right_Arithmetic
|
| Kotlin | shl |
shr
|
| Fortran | SHIFTL |
SHIFTA [note 2]
|
| Standard ML | << |
~>>
|
| Verilog | <<< |
>>> [note 3]
|
| OpenVMS macro language | @[note 4] | |
| Scheme | arithmetic-shift[note 5]
| |
| Common Lisp | ash
| |
| OCaml | lsl |
asr
|
| Haskell | Data.Bits.shift[note 6]
| |
| VHDL | sla[note 7] |
sra
|
| Assembly: Z80 | SLA[5] |
SRA
|
| Assembly: x86 | SAL |
SAR
|
| Assembly: 68k | ASL |
ASR
|
| Assembly: RISC-V | sll, slli[6] |
sra, srai
|
In computer programming, an arithmetic shift is a shift operator, sometimes termed a signed shift (though it is not restricted to signed operands). The two basic types are the arithmetic left shift and the arithmetic right shift. For binary numbers it is a bitwise operation that shifts all of the bits of its operand; every bit in the operand is simply moved a given number of bit positions, and the vacant bit-positions are filled in. Instead of being filled with all 0s, as in logical shift, when shifting to the right, the leftmost bit (usually the sign bit in signed integer representations) is replicated to fill in all the vacant positions (this is a kind of sign extension).
Some authors prefer the terms sticky right-shift and zero-fill right-shift for arithmetic and logical shifts respectively.[7]
Arithmetic shifts can be useful as efficient ways to perform multiplication or division of signed integers by powers of two. Shifting left by n bits on a signed or unsigned binary number has the effect of multiplying it by 2n. Shifting right by n bits on a two's complement signed binary number has the effect of dividing it by 2n, but it always rounds down (towards negative infinity). This is different from the way rounding is usually done in signed integer division (which rounds towards 0). This discrepancy has led to bugs in a number of compilers.[8]
For example, in the x86 instruction set, the SAR instruction (arithmetic right shift) divides a signed number by a power of two, rounding towards negative infinity.[9] However, the IDIV instruction (signed divide) divides a signed number, rounding towards zero. So a SAR instruction cannot be substituted for an IDIV by power of two instruction nor vice versa.
Formal definition
[edit]The formal definition of an arithmetic shift, from Federal Standard 1037C is that it is:
A shift, applied to the representation of a number in a fixed radix numeration system and in a fixed-point representation system, and in which only the characters representing the fixed-point part of the number are moved. An arithmetic shift is usually equivalent to multiplying the number by a positive or a negative integral power of the radix, except for the effect of any rounding; compare the logical shift with the arithmetic shift, especially in the case of floating-point representation.
An important word in the FS 1073C definition is "usually".
Non-equivalence of arithmetic right shift and division
[edit]However, arithmetic right shifts are major traps for the unwary, specifically in treating rounding of negative integers. For example, in the usual two's complement representation of negative integers, −1 is represented as all 1's. For an 8-bit signed integer this is 1111 1111. An arithmetic right-shift by 1 (or 2, 3, ..., 7) yields 1111 1111 again, which is still −1. This corresponds to rounding down (towards negative infinity), but is not the usual convention for division.
It is frequently stated that arithmetic right shifts are equivalent to division by a (positive, integral) power of the radix (e.g., a division by a power of 2 for binary numbers), and hence that division by a power of the radix can be optimized by implementing it as an arithmetic right shift. (A shifter is much simpler than a divider. On most processors, shift instructions will execute faster than division instructions.) Large number of 1960s and 1970s programming handbooks, manuals, and other specifications from companies and institutions such as DEC, IBM, Data General, and ANSI make such incorrect statements[10][page needed].
Logical right shifts are equivalent to division by a power of the radix (usually 2) only for positive or unsigned numbers. Arithmetic right shifts are equivalent to logical right shifts for positive signed numbers. Arithmetic right shifts for negative numbers in N's complement (usually two's complement) is roughly equivalent to division by a power of the radix (usually 2), where for odd numbers rounding downwards is applied (not towards 0 as usually expected).
Arithmetic right shifts for negative numbers are equivalent to division using rounding towards 0 in ones' complement representation of signed numbers as was used by some historic computers, but this is no longer in general use.
Handling the issue in programming languages
[edit]The (1999) ISO standard for the programming language C defines the right shift operator in terms of divisions by powers of 2.[11] Because of the above-stated non-equivalence, the standard explicitly excludes from that definition the right shifts of signed numbers that have negative values. It does not specify the behaviour of the right shift operator in such circumstances, but instead requires each individual C compiler to define the behaviour of shifting negative values right.[note 8]
Like C, C++ had an implementation-defined right shift for signed integers until C++20. Starting in the C++20 standard, right shift of a signed integer is defined to be an arithmetic shift.[13]
Applications
[edit]In applications where consistent rounding down is desired, arithmetic right shifts for signed values are useful. An example is in downscaling raster coordinates by a power of two, which maintains even spacing. For example, right shift by 1 sends 0, 1, 2, 3, 4, 5, ... to 0, 0, 1, 1, 2, 2, ..., and −1, −2, −3, −4, ... to −1, −1, −2, −2, ..., maintaining even spacing as −2, −2, −1, −1, 0, 0, 1, 1, 2, 2, ... In contrast, integer division with rounding towards zero sends −1, 0, and 1 all to 0 (3 points instead of 2), yielding −2, −1, −1, 0, 0, 0, 1, 1, 2, 2, ... instead, which is irregular at 0.
Notes
[edit]- ^ The
>>operator in C and C++ is not necessarily an arithmetic shift. Usually it is only an arithmetic shift if used with a signed integer type on its left-hand side. If it is used on an unsigned integer type instead, it will be a logical shift. - ^ Fortran 2008.
- ^ The Verilog arithmetic right shift operator only actually performs an arithmetic shift if the first operand is signed. If the first operand is unsigned, the operator actually performs a logical right shift.
- ^ In the OpenVMS macro language, whether an arithmetic shift is left or right is determined by whether the second operand is positive or negative. This is unusual. In most programming languages the two directions have distinct operators, with the operator specifying the direction, and the second operand is implicitly positive. (Some languages, such as Verilog, require that negative values be converted to unsigned positive values. Some languages, such as C and C++, have no defined behaviour if negative values are used.)[4][page needed]
- ^ In Scheme
arithmetic-shiftcan be both left and right shift, depending on the second operand, very similar to the OpenVMS macro language, although R6RS Scheme adds both-rightand-leftvariants. - ^ The
Bitsclass from Haskell'sData.Bitsmodule defines bothshifttaking a signed argument andshiftL/shiftRtaking unsigned arguments. These are isomorphic; for new definitions the programmer need provide only one of the two forms and the other form will be automatically defined in terms of the provided one. - ^ The VHDL arithmetic left shift operator is unusual. Instead of filling the LSB of the result with zero, it copies the original LSB into the new LSB. While this is an exact mirror image of the arithmetic right shift, it is not the conventional definition of the operator, and is not equivalent to multiplication by a power of 2. In the VHDL 2008 standard this strange behavior was left unchanged (for backward compatibility) for argument types that do not have forced numeric interpretation (e.g., BIT_VECTOR) but 'SLA' for unsigned and signed argument types behaves in the expected way (i.e., rightmost positions are filled with zeros). VHDL's shift left logical (SLL) function does implement the aforementioned 'standard' arithmetic shift.
- ^ The C standard was intended to not restrict the C language to either ones' complement or two's complement architectures. In cases where the behaviours of ones' complement and two's complement representations differ, such as this, the standard requires individual C compilers to document the behaviour of their target architectures. The documentation for GNU Compiler Collection (GCC), for example, documents its behaviour as employing sign-extension.[12]
References
[edit]Cross-reference
[edit]- ^ "Bit manipulation - Dlang Tour". tour.dlang.org. Retrieved 2019-06-23.
- ^ "Operator Expressions: Arithmetic and Logical Binary Operators". doc.rust-lang.org. Retrieved 2022-11-13.
- ^ "Annotated Ada 2012 Reference Manual".
- ^ HP 2001.
- ^ "Z80 Assembler Syntax".
- ^ "The RISC-V Instruction Set Manual, Volume I: Unprivileged ISA" (PDF). GitHub. 2019-12-13. pp. 18–20. Archived (PDF) from the original on 2022-10-09. Retrieved 2021-08-07.
- ^ Thomas R. Cain and Alan T. Sherman. "How to break Gifford's cipher". Section 8.1: "Sticky versus Non-Sticky Bit-shifting". Cryptologia. 1997.
- ^ Steele Jr, Guy. "Arithmetic Shifting Considered Harmful" (PDF). MIT AI Lab. Archived (PDF) from the original on 2022-10-09. Retrieved 20 May 2013.
- ^ Hyde 1996, § 6.6.2.2 SAR.
- ^ Steele 1977.
- ^ ISOIEC9899 1999, § 6.5.7 Bitwise shift operators.
- ^ FSF 2008, § 4.5 Integers implementation.
- ^ ISOCPP20 2020, § 7.6.7 Shift operators.
Sources used
[edit]
This article incorporates public domain material from Federal Standard 1037C. General Services Administration. Archived from the original on 2022-01-22.
- Knuth, Donald (1969). The Art of Computer Programming, Volume 2 — Seminumerical algorithms. Reading, Mass.: Addison-Wesley. pp. 169–170.
- Steele, Guy L. (November 1977). "Arithmetic shifting considered harmful". ACM SIGPLAN Notices. 12 (11). New York: ACM Press: 61–69. doi:10.1145/956641.956647. hdl:1721.1/6090. S2CID 15420308. Archived from the original on September 22, 2017.
- "3.7.1 Arithmetic Shift Operator". VAX MACRO and Instruction Set Reference Manual. Hewlett-Packard Development Company. April 2001. Archived from the original on 2011-08-08.
{{cite book}}:|work=ignored (help) - Programming languages — C. ISO/IEC 9899:1999. International Organization for Standardization. 1999.
- Hyde, Randall (1996-09-26). "CHAPTER SIX: THE 80x86 INSTRUCTION SET (Part 3)". The Art of ASSEMBLY LANGUAGE PROGRAMMING. Archived from the original on 2007-11-23. Retrieved 2007-11-28.
- "C Implementation". GCC manual. Free Software Foundation. 2008.
- "ISO/IEC 14882:2020(E) – Programming Language C++" (PDF). International Organization for Standardization. 2020.
Arithmetic shift
View on GrokipediaFundamentals
Definition
An arithmetic shift is a bitwise operation that shifts the bits of a binary number left or right by a specified number of positions, with the key characteristic of preserving the sign of the number when operating on signed integers represented in two's complement form.[5][6] In this representation, the most significant bit (MSB) serves as the sign bit: 0 for positive (including zero) and 1 for negative values.[7] To understand arithmetic shifts, consider the binary representation of signed integers using two's complement, the predominant method in modern computing architectures. For an n-bit integer, positive numbers are encoded in standard binary, while negative numbers are formed by inverting all bits of the positive equivalent and adding 1; this allows arithmetic operations to treat positive and negative values uniformly without separate sign handling.[7][8] In an arithmetic left shift, vacated bit positions on the right are filled with zeros. In an arithmetic right shift, vacated bit positions on the left are filled by replicating the sign bit, ensuring the numerical value remains correctly interpreted as signed—zeros for positive numbers and ones for negative ones.[5][9] This contrasts with logical shifts, which always fill with zeros regardless of sign.[6] For example, consider an 8-bit positive integer 00001010₂ (decimal 10). An arithmetic left shift by 1 position yields 00010100₂ (decimal 20), filling the right with 0; a right shift by 1 yields 00000101₂ (decimal 5), filling the left with 0 due to the positive sign.[5] For a negative 8-bit integer like 11110110₂ (decimal -10 in two's complement), a right shift by 1 becomes 11111011₂ (decimal -5), filling the left with 1s to extend the sign and preserve negativity.[6] Left shifts on negative numbers fill with 0 on the right but may cause overflow if the sign bit shifts out.[5] Arithmetic shifts originated in early computer architectures to enable efficient signed arithmetic operations, notably in the IBM System/360 introduced in 1964, where instructions like Shift Right Arithmetic (SRA) and Shift Left Arithmetic (SLA) explicitly preserved the sign bit for fixed-point integers.[10]Comparison to logical shift
The logical shift operation treats the operand as an unsigned integer, filling any vacated bit positions with zeros during both left and right shifts, regardless of the original sign of the value.[11] In contrast, the arithmetic right shift preserves the sign of signed integers by filling vacated positions on the left with copies of the sign bit (0 for positive, 1 for negative), which maintains the numerical value's intended signed magnitude during division-like operations.[11] This difference becomes critical when processing signed data: a logical shift can inadvertently change the sign or produce an incorrect positive value, while an arithmetic shift ensures sign preservation.[12] To illustrate, consider an 8-bit two's complement representation where the value -4 is encoded as 11111100. A right shift by 1 bit using arithmetic shift fills with the sign bit (1), resulting in 11111110 (-2, preserving the negative sign and halving the magnitude). The same operation using logical shift fills with 0, yielding 01111111 (127, an unsigned positive value that alters the sign).[13]| Value | Binary (8-bit) | Operation | Arithmetic Right Shift Result | Logical Right Shift Result |
|---|---|---|---|---|
| Signed -4 | 11111100 | Right by 1 | 11111110 (-2) | 01111111 (127) |
Operations
Left shift
The arithmetic left shift operation moves each bit in a binary number to the left by a specified number of positions , filling the vacated rightmost bits with zeros while discarding any bits shifted out from the left in fixed-width representations such as registers or words.[13] This behavior is identical for both unsigned and signed integers, as the left shift does not depend on the sign bit for insertion.[15] In two's complement representation for signed integers, an arithmetic left shift by positions is mathematically equivalent to multiplying the original value by , as long as the result does not cause overflow within the fixed bit width.[16] The equation can be expressed as .[17] This equivalence holds because shifting left effectively scales the positional values of the bits by powers of 2, preserving the signed interpretation until overflow intervenes.[6] For example, consider the 8-bit two's complement representation of the positive integer 5, which is . Performing a left shift by 2 positions yields , equivalent to 20 in decimal, demonstrating multiplication by .[13] Similarly, for the negative integer -5, represented as , a left shift by 1 position results in , which is -10 in decimal, corresponding to multiplication by .[16] Overflow occurs in signed arithmetic if the shifted result exceeds the representable range for the bit width, potentially causing the sign bit to change and flipping the sign of the value (e.g., a positive number becoming negative or vice versa).[16] For instance, in 4-bit two's complement, shifting 7 () left by 1 produces (-2), as the overflowed bit sets the sign bit to 1.[13] Such behavior underscores the need to check for overflow in arithmetic computations using shifts.[15]Right shift
The arithmetic right shift operation moves the bits of a binary number to the right by a specified number of positions, n, while filling the vacated most significant bits (leftmost) with copies of the original sign bit to preserve the number's sign in two's complement representation.[13] This sign extension ensures that positive numbers remain positive and negative numbers remain negative after the shift.[6] The least significant n bits are discarded (shifted out), effectively truncating the lower-order bits.[18] For positive signed integers, an arithmetic right shift by n bits is equivalent to integer division by , as the operation aligns with standard unsigned right shifting in this case.[6] However, for negative signed integers, the shift performs a flooring division by , rounding toward negative infinity rather than toward zero, due to the sign bit replication which adjusts the magnitude downward.[18] For instance, shifting -5 (binary 11111011 in 8-bit two's complement) right by 1 bit yields -3 (11111101), since -5 divided by 2 is -2.5, and flooring gives -3.[6] Consider an 8-bit two's complement example with the positive number 20, represented as 00010100. An arithmetic right shift by 2 bits moves the bits right, fills the left with 0 (sign bit), and discards the last two bits (00), resulting in 00000101, which is 5—equivalent to 20 divided by 4.[13] For the negative number -20, represented as 11101100, the same shift by 2 bits moves the bits right, fills the left with 1 (sign bit), and discards the last two bits (00), yielding 11111011, which is -5—consistent with flooring division of -20 by 4 to -5.[18] This truncation of least significant bits in signed arithmetic thus implements a form of division that prioritizes sign preservation over symmetric rounding.[13]Properties
Sign preservation
In two's complement representation, the arithmetic right shift operation preserves the sign of a signed integer by replicating the sign bit (the most significant bit) into the vacated positions on the left, ensuring that a negative input remains negative and a positive input remains positive.[5][9] For example, the 4-bit two's complement value -4 (binary 1100) shifted right by 1 bit becomes 1110 (-2), with the sign bit '1' replicated to maintain negativity.[5] This replication distinguishes arithmetic right shifts from logical right shifts, which fill with zeros and could alter the sign interpretation.[19] Arithmetic left shifts generally preserve the sign as well, since they fill the least significant bits with zeros and shift the sign bit leftward, but this holds only until overflow occurs, at which point the sign bit may change if the result exceeds the representable range.[5] For instance, in an 8-bit two's complement system, shifting -1 (binary 11111111) left by 1 bit yields 11111110 (-2), preserving the negative sign, but further shifts can lead to overflow where the sign bit flips if the magnitude grows beyond the format's limits.[5] Edge cases highlight the behavior clearly: shifting the all-zero pattern (representing 0) right arithmetically yields 0 regardless of shift amount, as the sign bit is 0 and replicates zeros; conversely, shifting the all-one pattern (representing -1) right replicates 1s, keeping the result as -1.[5] In multi-word integers, such as extending a 32-bit signed value to 64 bits, arithmetic right shifts propagate the sign bit across word boundaries via sign extension, filling higher bits with the replicated sign to maintain the correct negative or positive interpretation in the larger format.[20] These sign preservation properties enable efficient implementation of signed arithmetic operations, such as division by powers of 2, without requiring complex full adders for sign handling, as the replicated bits inherently adjust the magnitude while keeping the sign intact.[5] In contrast, for unsigned integers, the sign bit holds no interpretive meaning, so arithmetic shifts are typically replaced by logical shifts that zero-fill, avoiding unnecessary sign replication.[9]Relation to multiplication and division
The arithmetic left shift operation by bits on an integer , denoted , is exactly equivalent to multiplication by , assuming no overflow occurs in the representation.[21] This holds for both signed and unsigned integers, as the shift fills the vacated least significant bits with zeros, effectively scaling the value by the power of two without altering the sign bit's influence in two's complement.[22] In contrast, the arithmetic right shift approximates division by but implements a floor division, always rounding the quotient toward negative infinity. For nonnegative , this matches the typical integer division semantics of truncation toward zero. However, for negative , the result differs due to the flooring behavior; for example, in two's complement, , whereas the true division would truncate to under toward-zero rounding.[18] This discrepancy arises because the sign extension in arithmetic right shift preserves the negative sign while shifting, effectively rounding down rather than toward zero.[23] These differences highlight key non-equivalences in signed arithmetic, particularly in rounding modes across systems. Modern languages like C and C++ specify signed integer division to truncate toward zero, independent of the shift operation's flooring. Arithmetic right shift, however, consistently floors, leading to potential mismatches for negative values unless adjusted.[18] Other modes, such as rounding toward positive or negative infinity, are not natively supported by shifts but can influence division in floating-point contexts or specific hardware. To simulate toward-zero division for using arithmetic right shift on negative odd integers, a common adjustment adds 1 post-shift when applicable:(x >> 1) + ((x < 0) && (x & 1) ? 1 : 0).[18] This corrects the flooring bias only in cases where the least significant bit indicates a fractional remainder requiring upward adjustment toward zero.
Implementation
In hardware
Arithmetic shifts are implemented in the arithmetic logic unit (ALU) of processors through dedicated shifter circuits that handle bit manipulations efficiently. These circuits often employ multiplexers (MUXes) arranged in layers to form a barrel shifter, enabling variable shift amounts (n) in a single clock cycle by routing bits through multiple stages of selection. For arithmetic right shifts, sign extension is achieved by wiring the sign bit (most significant bit) of the operand to the input lines that fill the vacated high-order positions, preserving the number's sign during the operation.[24][25][26] One of the earliest commercial implementations of arithmetic shifts appeared in the IBM System/360 mainframe architecture, introduced in 1964, which included instructions like Shift Left Arithmetic (SLA) and Shift Right Arithmetic (SRA) in its fixed-point instruction set to support signed integer operations. These instructions were designed to integrate seamlessly with the system's ALU for efficient handling of two's complement arithmetic, marking a significant advancement in hardware support for signed bit shifts.[10][27] In modern processors, arithmetic shifts are supported via specialized instructions that extend to both scalar and vector operations. For instance, the x86 architecture provides the SAR (Shift Arithmetic Right) instruction, which performs right shifts on registers while filling with the sign bit, and SIMD extensions like MMX and SSE include packed variants such as PSRAW for parallel arithmetic right shifts on multiple data elements. Similarly, RISC architectures like ARM incorporate the ASR (Arithmetic Shift Right) instruction, which differs from its logical counterpart LSR (Logical Shift Right) by sign-extending the operand, enabling efficient signed division in resource-constrained environments. In contrast to CISC designs like x86, which may combine shifts with other operations in complex instructions, RISC approaches prioritize simple, single-cycle shifts to enhance pipeline efficiency and reduce power consumption in embedded systems.[28][29]In programming languages
In C and C++, the right-shift operator>> performs an arithmetic shift for signed integer types, preserving the sign bit by filling vacated positions with copies of the sign bit, while it performs a logical shift for unsigned types by filling with zeros.[30] This behavior for signed integers was implementation-defined prior to C++20 but has been standardized as arithmetic since then, rounding toward negative infinity for negative values.[30] To ensure logical shifting on signed types, programmers often cast to unsigned explicitly, such as (unsigned int)x >> n.[30]
In Java, the >> operator implements an arithmetic right shift for all integer types, sign-extending the result to preserve the sign, while the >>> operator provides a logical right shift by zero-filling regardless of sign.[31] For positive values, this corresponds to truncation toward zero in division by powers of two; for negative values, it truncates toward negative infinity due to sign extension.[31] The Java Language Specification defines this precisely for 32-bit int and 64-bit long types, with the shift amount masked to the appropriate bit width (five bits for int, six for long).[31]
Python's >> operator performs an arithmetic right shift on integers, treating them as arbitrary-precision two's complement values and filling with the sign bit for negative numbers, equivalent to floor division by .[32] In JavaScript, bitwise operators including >> convert operands to 32-bit signed integers before operating, resulting in an arithmetic right shift that preserves the sign via sign extension; the result is then converted back to a floating-point number.[33]
Portability challenges arise primarily in C and C++, where the behavior of >> on signed negative integers remains implementation-defined in C (as per ISO C99 and later), potentially leading to logical instead of arithmetic shifts on some platforms, though most common compilers use arithmetic.[34] Endianness does not affect shift operations directly, but multi-byte integer representations can complicate sign extension across architectures if shifts exceed the type's bit width, often requiring explicit masking of the shift amount to avoid undefined behavior.[30] To achieve portable arithmetic right shifts in C, one common approach is to cast to unsigned, perform the shift, and adjust based on the original sign bit.[35]
When using arithmetic right shifts for signed integer division by powers of two, the truncation toward negative infinity for negative values can deviate from toward-zero semantics in some languages, necessitating adjustments for consistent "true" division.[35] For positive or unsigned values seeking rounding up (ceiling division), a portable idiom in C/C++ and similar languages is (x + ((1U << n) - 1)) >> n, which adds the appropriate bias before shifting to handle the truncation correctly without branches.[35] In Java and Python, where arithmetic shifts are reliably defined, such fixes are less critical but may still be applied for specific rounding modes.[31]