bitwise operators
number sign detection
programming techniques
computer science
numeric analysis

Checking whether a number is positive or negative using bitwise operators

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In two's complement representation (used by virtually all modern CPUs), the most significant bit (MSB) is the sign bit: 0 for non-negative numbers and 1 for negative numbers. To check if a number is negative using bitwise operators, right-shift it by the number of bits minus one (n >> 31 for 32-bit integers) and check if the result is -1 or 1. Alternatively, AND the number with the sign bit mask (n & (1 << 31)). These bitwise checks are marginally faster than comparison operators but are primarily useful in low-level programming, embedded systems, and interview questions.

Two's Complement Representation

 
1Positive 5:  00000000 00000000 00000000 00000101
2Negative 5:  11111111 11111111 11111111 11111011
3
4Positive 1:  00000000 00000000 00000000 00000001
5Negative 1:  11111111 11111111 11111111 11111111
6
7Zero:        00000000 00000000 00000000 00000000

In a 32-bit signed integer, bit 31 (the leftmost) is the sign bit. Positive numbers have 0 as the MSB, negative numbers have 1. Zero has a sign bit of 0, so bitwise checks classify it as non-negative.

Method 1: Right Shift

c
1#include <stdio.h>
2
3int is_negative(int n) {
4    // Arithmetic right shift fills with the sign bit
5    // For 32-bit int: shifts sign bit to position 0
6    return (n >> 31) & 1;
7}
8
9int main() {
10    printf("%d -> %s\n", 42, is_negative(42) ? "negative" : "non-negative");
11    printf("%d -> %s\n", -7, is_negative(-7) ? "negative" : "non-negative");
12    printf("%d -> %s\n", 0, is_negative(0) ? "negative" : "non-negative");
13    // 42 -> non-negative
14    // -7 -> negative
15    // 0 -> non-negative
16    return 0;
17}

n >> 31 performs an arithmetic right shift, filling new bits with the sign bit. For negative numbers, the result is all 1s (which is -1 in two's complement). ANDing with 1 isolates the sign bit.

Method 2: AND with Sign Bit Mask

c
1#include <stdio.h>
2#include <stdbool.h>
3
4bool is_negative(int n) {
5    // AND with the sign bit position
6    return (n & (1 << 31)) != 0;
7}
8
9// For 64-bit integers
10bool is_negative_64(long long n) {
11    return (n & (1LL << 63)) != 0;
12}
13
14int main() {
15    printf("%d: %s\n", 5, is_negative(5) ? "neg" : "pos");
16    printf("%d: %s\n", -5, is_negative(-5) ? "neg" : "pos");
17    // 5: pos
18    // -5: neg
19    return 0;
20}

1 << 31 creates a mask with only bit 31 set (10000000...0). ANDing with this mask extracts the sign bit. If non-zero, the number is negative.

Method 3: XOR-Based Sign Comparison

c
1#include <stdio.h>
2
3// Check if two numbers have different signs
4int different_signs(int a, int b) {
5    return (a ^ b) < 0;
6    // XOR: if sign bits differ, MSB of result is 1 -> negative
7}
8
9int main() {
10    printf("5, -3: %s signs\n",
11        different_signs(5, -3) ? "different" : "same");
12    printf("5, 3: %s signs\n",
13        different_signs(5, 3) ? "different" : "same");
14    // 5, -3: different signs
15    // 5, 3: same signs
16    return 0;
17}

XOR produces a 1 in each bit position where the inputs differ. If two numbers have different signs, their MSBs differ, making the XOR result negative.

Implementation in Multiple Languages

python
1# Python — arbitrary precision integers
2def is_negative(n):
3    return n < 0  # Bitwise sign check doesn't work for arbitrary-precision ints
4
5# For fixed-width behavior, use ctypes
6import ctypes
7def is_negative_32bit(n):
8    return ctypes.c_int32(n).value >> 31 & 1
java
1// Java — 32-bit int, guaranteed two's complement
2public static boolean isNegative(int n) {
3    return (n >> 31) != 0;
4    // Java guarantees arithmetic right shift for >>
5}
6
7// Using Integer.signum
8public static int sign(int n) {
9    return Integer.signum(n);  // Returns -1, 0, or 1
10}
javascript
1// JavaScript — bitwise operators work on 32-bit integers
2function isNegative(n) {
3    return (n >> 31) !== 0;
4    // >> is arithmetic right shift in JS (for 32-bit range)
5}
6
7// Using Math.sign
8console.log(Math.sign(-5));  // -1
9console.log(Math.sign(5));   // 1
10console.log(Math.sign(0));   // 0

Branchless Absolute Value

c
1#include <stdio.h>
2
3// Compute absolute value without branching
4int abs_branchless(int n) {
5    int mask = n >> 31;          // 0 for positive, -1 for negative
6    return (n + mask) ^ mask;    // Flips bits and adds 1 for negative
7    // Equivalent: (n ^ mask) - mask
8}
9
10int main() {
11    printf("|5| = %d\n", abs_branchless(5));     // 5
12    printf("|-7| = %d\n", abs_branchless(-7));   // 7
13    printf("|0| = %d\n", abs_branchless(0));     // 0
14    return 0;
15}

The mask is 0x00000000 for non-negative numbers (no effect) and 0xFFFFFFFF for negative numbers (inverts all bits). This is a classic branchless optimization used in performance-critical code.

Branchless Min/Max Using Sign Bit

c
1// Branchless minimum of two integers
2int branchless_min(int a, int b) {
3    int diff = a - b;
4    int sign = (diff >> 31) & 1;  // 1 if a < b, 0 otherwise
5    return a * sign + b * (1 - sign);
6    // Or: return b + (diff & (diff >> 31));
7}
8
9// Branchless maximum
10int branchless_max(int a, int b) {
11    int diff = a - b;
12    int sign = (diff >> 31) & 1;
13    return b * sign + a * (1 - sign);
14}

Common Pitfalls

  • Zero is classified as non-negative: Zero's sign bit is 0, so (0 >> 31) & 1 returns 0. If your logic needs to distinguish positive, negative, and zero as three categories, add a separate zero check: n == 0.
  • Undefined behavior with signed right shift in C: The C standard does not guarantee arithmetic right shift for signed integers — it is implementation-defined. Most compilers (GCC, Clang, MSVC) use arithmetic right shift, but portable code should avoid relying on this. Use (n & (1 << 31)) != 0 instead.
  • Integer overflow in subtraction: a - b overflows when a and b have large opposite signs (e.g., INT_MAX - INT_MIN). Branchless min/max using subtraction fails in these edge cases. Check for overflow or cast to a wider type first.
  • Python integers have arbitrary precision: Python int is not fixed-width, so n >> 31 does not isolate the sign bit for numbers larger than 32 bits. Negative numbers in Python have infinite leading 1s conceptually. Use n < 0 for sign checking in Python.
  • Logical vs arithmetic right shift: In Java, >> is arithmetic (sign-extending) and >>> is logical (zero-filling). (-1 >>> 31) returns 1, while (-1 >> 31) returns -1. In C, there is only >> and its behavior depends on the implementation for signed types.

Summary

  • The sign bit (MSB) is 0 for non-negative and 1 for negative in two's complement
  • Use (n >> 31) & 1 to extract the sign bit (assumes arithmetic right shift)
  • Use n & (1 << 31) for a portable sign bit check in C
  • XOR of two numbers reveals whether they have different signs
  • Branchless absolute value uses mask = n >> 31; (n ^ mask) - mask
  • These techniques are useful in embedded systems and performance-critical code, but prefer n < 0 for general-purpose readability

Course illustration
Course illustration

All Rights Reserved.