4 Billion If Statements

What happens when you take a beginner's naive approach to checking if a number is even or odd — using individual if statements — and scale it to 4 billion? A hilarious journey through metaprogramming, compiler limits, and raw machine code generation.

I recently stumbled upon a screenshot of some beginner code. The programmer was checking whether a number is even or odd using individual if statements:

if (number == 0) printf("even");
if (number == 1) printf("odd");
if (number == 2) printf("even");
if (number == 3) printf("odd");
...

Of course, everyone knows you should use the modulo operator: number % 2 == 0. But I got curious — what if we actually scaled this naive approach up? How far can we take it?

8-Bit: A Warm-Up

For an 8-bit number, we only need 256 if statements. I wrote a Python script to generate the C source code:

print("/* Copyright 2023. Any unauthorized distribution of this source code")
print("   will be prosecuted to the fullest extent of the law */")

print("#include <stdio.h>")
print("#include <stdint.h>")
print("#include <stdlib.h>")

print("int main(int argc, char* argv[])")
print("{")
print("    uint8_t number = atoi(argv[1]); // No problems here")

for i in range(2**8):
    print("    if (number == "+str(i)+")")
    if i % 2 == 0:
        print("        printf(\"even\\n\");")
    else:
        print("        printf(\"odd\\n\");")

print("}")

The generated C code looks like this:

/* Copyright 2023. Any unauthorized distribution of this source code 
   will be prosecuted to the fullest extent of the law */
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
    uint8_t number = atoi(argv[1]); // No problems here
    if (number == 0)
        printf("even\n");
    if (number == 1)
        printf("odd\n");
    if (number == 2)
        printf("even\n");
    if (number == 3)
        printf("odd\n");
    ...
    if (number == 255)
        printf("odd\n");
}

Compiles instantly, runs perfectly. A 256-line program is nothing for a modern compiler. Easy.

8-bit result

16-Bit: Getting Bigger

For 16-bit numbers, we need 65,536 if statements. The Python generator is almost identical — just change uint8_t to uint16_t and 2**8 to 2**16.

The resulting C file is about 130,000 lines. It compiles in a few seconds and produces a ~2 MB executable. Still works flawlessly. The compiler doesn't even break a sweat.

32-Bit: Where Things Get Interesting

Now the real fun begins. For 32-bit numbers, we need 4,294,967,296 if statements. Four billion.

The Python script runs for a while and produces a C source file that is 330 gigabytes. Three hundred and thirty gigabytes of if statements.

Let's try to compile it. I fire up MSVC (Microsoft's C compiler) and... it crashes. The compiler runs out of heap memory trying to parse this monster. Even with maximum memory settings, it can't handle a 330 GB source file.

But there's another problem. Even if the compiler could handle it, the resulting Windows executable (.exe) can't exceed 4 GB due to the PE format limitation. Our code alone would be tens of gigabytes.

It seems like we've hit a wall. But this is where it gets creative.

The Nuclear Option: Generating Machine Code Directly

If the compiler can't handle our code, we'll skip the compiler entirely. We'll generate raw machine code — x86-64 instructions — directly from Python, and execute them.

First, let's figure out the assembly. The function takes a number in the ECX register (Windows x64 calling convention) and returns 1 for even, 0 for odd in EAX:

; Argument is in ECX, return value in EAX
XOR EAX, EAX       ; Set EAX to 0 (return value for odd)
CMP ECX, 0h         ; Compare argument with 0
JNE 3h              ; Skip next two instructions if not equal
INC EAX             ; If even, set return value to 1
RET                 ; Return
CMP ECX, 1h         ; Compare argument with 1
JNE 2               ; Skip next instruction if not equal
RET                 ; Return value for odd is already in EAX, just return
; Insert the remaining 2...2^32-1 comparisons here
RET                 ; Emergency return

For even numbers, we need: CMP (6 bytes) + JNE (2 bytes) + INC (2 bytes) + RET (1 byte) = 11 bytes. For odd numbers: CMP (6 bytes) + JNE (2 bytes) + RET (1 byte) = 9 bytes. Average 10 bytes per number, times 4 billion numbers = roughly 40 GB of binary code.

Here's the Python script that generates this binary:

import struct

with open('isEven.bin', 'wb') as file:
   
    file.write(b"\x31\xC0")                     # XOR EAX, EAX

    for i in range(2**32):
        ib = struct.pack("<I", i)               # Encode i as 32-bit little-endian integer

        file.write(b"\x81\xF9" + ib)            # CMP ECX, i

        if i%2 == 0:
            file.write(b"\x75\x03")             # JNE +3
            file.write(b"\xFF\xC0")             # INC EAX
            file.write(b"\xC3")                 # RET
        else:
            file.write(b"\x75\x01")             # JNE +1
            file.write(b"\xC3")                 # RET

    file.write(b"\xC3")                         # Emergency RET

This script runs for a good while and produces a 40 GB binary file. Now we need to execute it.

Executing 40 GB of Machine Code

We can't just load 40 GB into memory — most machines don't have that much RAM. Instead, we use memory-mapped file I/O. On Windows, the CreateFileMapping and MapViewOfFile APIs let us treat a file on disk as if it were in memory. The OS will load pages from disk on demand.

The key trick: we open the file with GENERIC_EXECUTE permission and map it with PAGE_EXECUTE_READ. This tells Windows to treat the file contents as executable code. Then we simply cast the memory pointer to a function pointer and call it:

#include <stdio.h>
#include <Windows.h>
#include <stdint.h>

int main(int argc, char* argv[])
{
    uint32_t number = strtoul(argv[1], NULL, 10); // No problems here

    // Open the code file
    HANDLE binFile = CreateFileA(
                        "isEven.bin",
                        GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ,
                        NULL,
                        OPEN_EXISTING,
                        FILE_ATTRIBUTE_NORMAL,
                        NULL);
   
    // Get the 64-bit file size
    LARGE_INTEGER codeSize;
    GetFileSizeEx(binFile, &codeSize);

    // Create a memory mapping of the file
    HANDLE mapping = CreateFileMapping(
                        binFile,
                        NULL,
                        PAGE_EXECUTE_READ,
                        0,
                        0,
                        NULL);

    // Get a pointer to the code
    LPVOID code = MapViewOfFile(
                    mapping, FILE_MAP_EXECUTE | FILE_MAP_READ,
                    0,
                    0,
                    codeSize.QuadPart);

    // Create a function pointing to the code
    int (*isEven)(int) = (int(*)(int))code;

    if (isEven(number))
        printf("even\n");
    else
        printf("odd\n");

    CloseHandle(binFile);
}

The Results

And it works! For small numbers (near 0), the result comes back in milliseconds — those comparisons are at the very beginning of the 40 GB file and are already in the memory cache. For numbers near 2^32 (like 4,294,967,295), it takes about 10 seconds — the OS has to page through nearly the entire file from disk to find the matching comparison.

So there you have it. We successfully implemented an even/odd checker using 4 billion if statements. Is it practical? Absolutely not. Is it beautiful? In its own terrible way — absolutely yes.

Final result screenshot

The entire project is a celebration of the idea that any sufficiently absurd approach can technically work if you throw enough creativity (and disk space) at it. Sometimes the journey matters more than the destination — especially when the destination is a 40 GB binary file that checks if a number is even.