Bit Shifts: Move Bits Without Rotating Them

I treat bit shifts as movement within a declared type width. Vacant positions are filled with zero, and shifted-out bits don’t wrap around. Casting the input before shifting can change the available width.

Gouache painting: a short wooden rack holds eight cream balls in one row
A brass armillary sphere beside tied paper packets, a wooden case and folded cloth.

Read the ordinary one-position shift

The first row starts with tinyint five. A left shift by one returns ten, while a right shift returns two. The same left shift on an int input also returns ten for this small value.

I’d keep the input type visible even when those results agree. Friendly low values don’t expose every width boundary. I’d explain a shift using its declared type. One example that fits several types doesn’t establish their shared boundary behavior.

WITH Inputs AS
(
 SELECT CaseId,CAST(InputValue AS tinyint) AS InputValue,ShiftAmount
 FROM (VALUES (1,5,1),(2,128,1),(3,5,-1),(4,5,9),
              (5,CAST(NULL AS int),1)) v(CaseId,InputValue,ShiftAmount)
)
SELECT CaseId,InputValue,ShiftAmount,
       LEFT_SHIFT(InputValue,ShiftAmount) AS TinyLeft,
       RIGHT_SHIFT(InputValue,ShiftAmount) AS TinyRight,
       LEFT_SHIFT(CAST(InputValue AS int),ShiftAmount) AS WideLeft
FROM Inputs
ORDER BY CaseId;
Native SSMS results showing five left and right shift cases for tinyint and widened int, including negative shifts, large shifts and NULL.
Shifting tinyint 128 left by one discards the high bit and returns zero. Widening to int first preserves 256. Negative shifts reverse direction; NULL stays NULL. Open the result at full size.

Expose a bit that leaves the type

The second tinyint value is 128, which has its highest bit set. Shifting it left by one removes that bit from the eight-bit result, leaving zero. The int version instead returns 256.

The wider cast occurs before LEFT_SHIFT, so the function operates within the wider input type. Casting the tiny result afterward wouldn’t restore the discarded bit. I’d retain this row when deciding whether the calculation intends a fixed-width representation or a wider numeric result.

Bit shift rules to remember

Keep logical movement separate from rotation

Logical shifts fill vacant positions with zero. A shifted-out bit doesn’t reappear at the opposite end. That is different from a rotation operation that preserves the moved bit within the same width.

I wouldn’t use these functions as a substitute for rotation without a separate rule. The intended bit pattern matters more than whether the result looks numerically convenient. This example makes the width loss visible instead of hiding it behind a display-only representation.

Read a negative shift direction

The third row requests minus one. A negative amount shifts in the opposite direction. LEFT_SHIFT then returns the same value as a one-position right shift, while RIGHT_SHIFT moves left.

I’d keep that sign in the input column rather than describing the call only by its function name. A dynamic negative amount can reverse the intended direction. The argument contract should say whether negative requests are allowed or rejected by the application.

Test the amount against the width

A shift of nine exceeds the tinyint width, so both tiny results are zero. The int left shift can still retain the moved bits and returns 2560. The last row separately preserves NULL source input.

Those cases distinguish a known value shifted out of range from an unknown value. I’d retain both when validating a dynamic operation. Filling a NULL result with zero would erase a difference that the displayed inputs currently make clear.

Choose the supported interface deliberately

LEFT_SHIFT and RIGHT_SHIFT are available in SQL Server 2022 and later. This query uses their function forms and performs no writes. Each output’s type follows its source expression, including the explicitly widened int calculation.

I’d compare all five complete tuples on the target instance before reusing the expression. This small test doesn’t establish a business flag mapping or a general overflow policy. It states the movement, width and sign rules that the caller must use intentionally.

Name the type before you shift, and the bits stay where you expect.

A shift is not a rotation, it is movement that can discard bits outside the declared width.

Published by Pinal Dave on SQLAuthority. More of my work at pinaldave.com.


Discover more from SQL Authority with Pinal Dave

Subscribe to get the latest posts sent to your email.

SQL Datatype, SQL Function, SQL Scripts
Previous Post
Untested Backup: The Joke That Ends With a Resignation Letter
Next Post
Least Privilege for Application Logins

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.