4 billion if statements (2023)

2025/12/07 0:34

4 billion if statements (2023)

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:

この記事では、8ビット整数のパリティをチェックするブルートフォースCプログラムが、ソースコードまたはマシンコードで網羅的な

if
比較を自動生成することで、より大きいビット幅へスケールできることを示しています。10ビットまでしか機能しない手書きの
if
文チェーンから始め、著者はPythonを使って8ビット値に対して全256ケースを網羅した約130 k行のCファイルを生成します。16ビットに拡張すると、同じソースサイズから約2 MBの実行可能ファイルが得られます。32ビットにスケールすると、約330 GBのCファイルと約2 MBのバイナリが作成されますが、MSVCは16 777 215というヒープ空間制限で行134,397,076でクラッシュします。Windows PE形式も4 GBまでしかバイナリをロードできないため、330 GBのソースは単一実行ファイルとして読み込めません。これらの制約を回避するために、著者は全4 294 967 296個の32ビット値をループ処理するアセンブリルーチンを書きました。生成されたマシンコードは約40 GBで、
CreateFileMapping
/
MapViewOfFile
でメモリマップできます。
atoi
パースバグ(
strtoul
に置換)を修正した後、プログラムは32ビット数値の偶奇判定をすべて正しく行い、Core i5‑12600K上で約10秒かかります。これらの実験は、Windows上でのコード生成の実用的な限界―コンパイラヒープ制限、OSファイルサイズ制限、および実行形式制限―を明らかにし、網羅的ケース列挙が本番コードでは通常非現実的であることを示し、開発者に大規模決定テーブル用のより効率的なアルゴリズムやツールを探すよう促します。

本文

以下は、元の英語テキストを日本語に訳したものです。
コードブロックはそのまま残し、不要な改行や「…」などの記号は削除しています。


ストーリー

電車でソーシャルメディアを調べているときに、偶然このスクリーンショットを見つけました。
もちろん、それに対して新人プログラマーが古典的なコンピュータサイエンスの問題「剰余演算」を解く試みを非難する悪意あるコメントが連続で寄せられました。

AI が人間の仕事を置き換え、コードへの考え方を変えている今、私たちは業界に新しい血を取り入れるべきだと感じています。実際、このコードは時間‑メモリトレードオフの典型例です。あなたは自分の時間だけでなく、コンピュータのメモリや時間も使っているのです―本当に素晴らしいアルゴリズムですね!

そこで私は「数が奇数か偶数か」を比較のみで判定するアイデアを実際に試すために、C 言語で実装しようとしました。性能重視なので、現在最も高速だと言われる C を選びました(デニス・リッチーのビジョンのおかげです)。

1. 手書きで始める

/* Copyright 2023. All unauthorized distribution of this source code 
   will be persecuted 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 == 4) printf("even\n");
    if (number == 5) printf("odd\n");
    if (number == 6) printf("even\n");
    if (number == 7) printf("odd\n");
    if (number == 8) printf("even\n");
    if (number == 9) printf("odd\n");
    if (number == 10) printf("even\n");
}

コンパイルして

/Od
(最適化無効)で実行すると、期待通りに動きます。

PS > cl.exe /Od program.c
PS > .\program.exe 0 
even
PS > .\program.exe 4
even
PS > .\program.exe 3
odd
PS > .\program.exe 7
odd

しかし、さらにテストすると問題が出てきました。

PS > .\program.exe 50
PS > .\program.exe 11
PS > .\program.exe 99

何も出力されません。10 より大きい数は動作しないのです。コードを見直すと、最後の

if
の後にさらに多くの
if
が必要だと分かります。

2. メタプログラミングで拡張

そこで「if 文」を別言語で生成することにしました。最遅の言語といわれる Python を使います(ロス・ヴァン・デル・ガッソムのおかげです)。

print("/* Copyright 2023. All unauthorized distribution of this source code")
print("   will be persecuted 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("}")

これで 8‑ビット整数全てに対して正しく判定できる C プログラムが生成されます。

PS > python programmer.py > program.c
PS > cl.exe /Od program.c
PS > .\program.exe 99
odd
PS > .\program.exe 50
even
PS > .\program.exe 240
even
PS > .\program.exe 241
odd

3. 16‑ビットへ拡張

print("    uint16_t number = atoi(argv[1]); // No problems here")
…
for i in range(2**16):

これで約 13 万行の C ファイルができ、コンパイルすると実行ファイルは約 2 MB。
私のゲーム PC では 31.8 GB のメモリがあるので問題ありません。

4. 32‑ビットへ挑戦

print("    uint32_t number = atoi(argv[1]); // No problems here")
…
for i in range(2**32):

Python に任せた結果、約 330 GB の C ファイルができました。
コンパイルすると次のようになります。

PS > cl /Od program.c
Microsoft (R) C/C++ Optimizing Compiler Version 19.32.31329 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

program.c
program.c(134397076): warning C4049: compiler limit: terminating line number emission
program.c(134397076): note: Compiler limit for line number is 16777215
program.c(41133672): fatal error C1060: compiler is out of heap space

パッチャーは失敗。さらに、PE(Portable Executable)フォーマットは 4 GB を超えることができません。32‑ビットの比較を 40 億個もエンコードするには大きすぎます。

5. 手動でアセンブリを書いてみる

それでも止まらないので、x86‑64 アセンブリで

IsEven
を手書きします。以下はその雰囲気です(実際のオペコードはここでは省略)。

; Argument is stored in ECX, return value in EAX
XOR     EAX, EAX          ; Set eax to zero (return value for odd number)
CMP     ECX, 0h           ; Compare arg to 0 
JNE     3h                ; Skip next two instructions if it wasn’t equal
INC     EAX               ; It was even, set even return value (1)
RET                     ; Return
CMP     ECX, 1h            ; Compare arg to 1
JNE     2                  ; Skip next instruction if not equal
RET                     ; Odd return value already in EAX, just RET
; add the next 2…2^32‑1 comparisons here
RET                       ; Fallback return

正確ではありませんが、機械語に手書きで変換すれば実行できます。

6. バイナリ生成

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")                         # Fallback RET

7. 実行ファイルにマップして呼び出す

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

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

    /* Open code file */
    HANDLE binFile = CreateFileA(
        "isEven.bin",
        GENERIC_READ | GENERIC_EXECUTE,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL);

    /* Get 64‑bit size of file */
    LARGE_INTEGER codeSize;
    GetFileSizeEx(binFile, &codeSize);

    /* Create memory map 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 that points to the code */
    int (*isEven)(int) = (int(*)(int)code;

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

    CloseHandle(binFile);
}

これで という状態に到達します。
(ここは自由に補完しても構いません。)

同じ日のほかのニュース

一覧に戻る →

2025/12/13 5:57

GNU Unifont

2025/12/13 7:02

Show HN: Tiny VM sandbox in C with apps in Rust, C and Zig

## Japanese Translation: uvm32 は、単一の C ファイルで書かれたミニマリストで依存関係を持たない仮想マシンサンドボックスです。 STM32L0 のような非常に小型のマイクロコントローラ上で動作し、4 KB 未満のフラッシュと 1 KB の RAM を使用します。静的割り当てのみで非同期設計となっています。 この VM は RISC‑V のサブセットを実装しており、軽量な管理インタフェースを公開しています。「if‑this‑then‑that」ロジックのために Lua、Duktape、MicroPython などの軽量スクリプトエンジンを置き換え、信頼できないコンポーネントや不安定な部品をサンドボックス化し、ターゲットコンパイラなしでモダン言語の「一度書けばどこでも実行できる」スクリプトを書けるようにすることが目的です。 主な特徴: - バイトコードアプリは C、Zig、Rust、またはアセンブリで記述可能。 - 非ブロッキングでシンプルな実行モデル。安全かつ最小限の型付けを備えた FFI を使用し、ホスト IO(stdio/ネットワーク)は想定していません。 - デザインは高速よりも安全性を優先しています。 - すべてのソースコードは `uvm32/` ディレクトリにあります。最小限のホスト例は `host‑mini` にあり、より高度なホストは `host/`、`host-parallel`、`host-arduino` にあります。 サンプルアプリケーションは VM の機能を示しています(C: helloworld, heap, conio, lissajous, maze, fib, sketch; Zig: zig‑mandel, zigtris, zigalloc, zigdoom; Rust: rust‑hello; アセンブリ: hello‑asm)。 ビルドとテスト用の Dockerfile が提供されており、`make dockerbuild`、`make dockershell` で構築・起動し、その後 `make` を実行してサンプルをコンパイル・実行します。ドキュメントはヘッダファイル `uvm32/uvm32.h` と `doc/README.md` にあります。本プロジェクトは MIT ライセンスで公開されています。

2025/12/13 5:15

Rats Play DOOM

## Japanese Translation: > **概要:** > 著者らは、ラットがDOOMをプレイできる完全にオープンソースの仮想現実装置をリリースしました。ゼロから構築されたこのシステムには、ハードウェア設計・ファームウェア・ソフトウェアがGitHubに掲載されており、他研究室でも簡単に再現または改良できます。バージョン 1(v1)はニューヨークのヴィクトール・トー氏によって開発され、ラットにDOOMコリドーを走行させるよう訓練しました。この実装はViceとPC Gamerで紹介されました。 > > 改良版(v2)はよりモジュラー化され、180°×80°の視野を持つ折りたたみ可能なAMOLEDスクリーン、新しいボールドライバー、強化された給餌器、ゲームイベントに同期した正確な10 µLの砂糖水投与が可能な改良リワード回路を備えています。追加センサーとランニングマシンのボール周囲に設置された光学フロー運動捕捉システムでトラッキング精度が向上しています。 > > ソフトウェアはPythonベースのモジュラースタック(arena_scenario.py)で、PC上で実行され、Raspberry PiとTCP経由で通信します。Piはリアルタイムセンサー読み取り・ボール駆動・リワード制御を担当します。すべてのコンポーネントはGitHubに文書化されており、3Dプリント可能なパーツや回路図も公開されています。 > > チーム(ヴィクトール・トー=ゲーマーラットコーチ、サンドル・マクラ=電気技師、アコス・ブラシュェク=ドキュメントリード)は、ラットが約2週間で慣れることを示しましたが、完全な訓練はまだ完了していません。 > > 現在の制限として、自動キャリブレーションスイートが無いため、ユーザーはセンサーの整列とリワードタイミングを手動で検証する必要があります。 > > 今後の課題は完全な訓練プロトコルの完成、キャリブレーションツールの改良、および他の行動タスクや種へ装置を拡張することです。低コストで完全にオープンなプラットフォームを提供することで、このプロジェクトは世界中の神経科学研究室の参入障壁を下げ、動物VR実験に依存する研究のスピードアップに寄与できる可能性があります。