Is < faster than <= in C++? Debunking Myths with Examples

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: A Myth That Has Lived for Decades

\n\n

If you've ever browsed Stack Overflow in the C++ section, you've probably seen the question: "Is < faster than <=?". This question has garnered thousands of views and dozens of pages of discussion. And it's no surprise — the topic of code optimization excites programmers of all levels.

\n\n

The logic seems ironclad: the < operator compares two numbers and returns a result, while <= does the same but additionally checks for equality. So, < must be faster, right? This is especially important for loops, where the comparison operation is performed millions of times.

\n\n

Today, we will settle this myth once and for all. You will learn:

\n
    \n
  • How operators actually work at the processor level.
  • \n
  • Why the compiler is your best friend (or enemy, if you don't trust it).
  • \n
  • When micro-optimization makes sense, and when it's a waste of time.
  • \n
\n\n

How do the < and <= operators work at the assembly level?

\n\n

To understand if there is a difference, we need to look "under the hood" — at what the compiler turns your C++ code into. Let's consider two simple functions:

\n\n
bool less_than(int a, int b) {\n    return a < b;\n}\n\nbool less_or_equal(int a, int b) {\n    return a <= b;\n}
\n\n

Let's compile them with g++ (without optimizations, flag -O0). Here's what we see in the assembly listing (x86-64):

\n\n
less_than(int, int):\n    cmp    edi, esi      ; compare a and b\n    setl   al            ; set al=1 if a < b (less)\n    ret\n\nless_or_equal(int, int):\n    cmp    edi, esi      ; compare a and b\n    setle  al            ; set al=1 if a <= b (less or equal)\n    ret
\n\n

See? The only difference is the instructions setl (set if less) and setle (set if less or equal). Both instructions execute in one processor clock cycle. On modern CPUs (Intel Core i7, AMD Ryzen), they have identical latency — 1 cycle.

\n\n

Conclusion #1: At the machine instruction level, there is no performance difference between < and <=. Period.

\n\n

What about loops? Surely there must be a difference there!

\n\n

The debate most often flares up around loops. Compare two approaches:

\n\n
// Option 1: with <\nfor (int i = 0; i < n; ++i) {\n    // do something\n}\n\n// Option 2: with <=\nfor (int i = 0; i <= n - 1; ++i) {\n    // do the same thing\n}
\n\n

Intuition suggests: the second option does an extra calculation n - 1. But let's see what happens after compiler optimization.

\n\n

Let's run a benchmark with g++ -O2 for n = 1 000 000 000:

\n\n
#include <iostream>\n#include <chrono>\n\nint main() {\n    const long long n = 1'000'000'000;\n    volatile long long sink = 0; // to prevent the compiler from removing the loop\n\n    auto start = std::chrono::high_resolution_clock::now();\n    \n    for (long long i = 0; i < n; ++i) {\n        sink += i;\n    }\n    \n    auto end = std::chrono::high_resolution_clock::now();\n    std::cout << "Time (<): " \n              << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()\n              << " ms\\n";\n\n    start = std::chrono::high_resolution_clock::now();\n    \n    for (long long i = 0; i <= n - 1; ++i) {\n        sink += i;\n    }\n    \n    end = std::chrono::high_resolution_clock::now();\n    std::cout << "Time (<=): " \n              << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()\n              << " ms\\n";\n\n    return 0;\n}
\n\n

Results on my machine (i7-107

Blogs

Book Recommendations