アルゴリズム — 歴史、性能、現在の位置づけ

lha が同梱しているのは LZHUF:1990 年代の LZ77 + 動的ハフマンで、「RAM 1 MiB の 286 での高速展開」を目指して調整され、SIMD が まだ存在しなかった時代に書かれたものです。このページは アルゴリズムそのもの、2026 年におけるそのコスト、そして なぜ別のプロジェクトの単一静的バイナリがその上に 乗っかるのか、を扱います。

アルゴリズム · 歴史 · 性能 · 現在 · まとめ

1. アルゴリズム

lha ファミリーの各圧縮方式(-lh0--lh7-、それと -lhd- のディレク トリヘッダ)は、共通する 2 段構成をしています:

  1. LZ77 風の文字列マッチング。入力中のバイト列 の繰り返しを探し、バイトをくり返す代わりに (distance, length) の後方参照を出力しま す。LZARI / LZHUF / ZIP / gzip / zstd / lz4 / 7-zip の「LZ」はすべてこの同じアイデアで、源流は Lempel & Ziv の 1977 年の論文です。
  2. エントロピーコーダ。リテラルと後方参照を ビット列に符号化します。ここで方式ごとに違いが出ます:
    • -lh1-LZARI: LZ77 + 算術符号(Okumura、1988)。
    • -lh5-LZHUF: LZ77 + 動的ハフマン(Tagawa、1990)。デフォ ルト方式。
    • -lh4--lh6--lh7--lzs- — エントロピー部分の実験的改良、または互換性 のために取っておかれた未使用符号。

静的 vs 動的ハフマン

LZHUF は静的ハフマン表をブロックごとに使います。 数 KB の入力ごとに再導出されます。この設計上の割り切り が、すべてのトレードオフを規定します:

ビット・シリアルの復号ループ(そしてなぜ遅いのか)

LZHUF の復号ループはビットストリームを1 ビットずつ 読み、小さな 2× 表を辿って次のシンボルを引き当てます。こ れは原理的にシリアルで、ビット n+1 はビット n の表引きが終わるまで読めません。

ANSI C のソースコードは 1995-2003 年のままで、SIMD イン トリンジックは入っていません:

$ grep -nEi '(mmx|sse|avx|simd|__m128i|__builtin_ia32)' upstream/lha/src/*.c
$                       # ヒットなし

LZ77 の length-distance コピーをベクトル化しても、展開で せいぜい 1.5–2 倍程度。ビット・シリアルのハフマン ループが天井です。展開をさらに速くするには、アルゴリズム を替えるしかなく、LZHUF をマイクロ最適化しても限界があ ります(詳しくは ベンチページ)。

2. 歴史 — 系譜

ホームページの歴史セクション が 1988-2022 の弧を詳しく語っているので、ここでは圧縮版 を:

3. 性能 — 3 つの軸

数字は 効率ベンチによる、kenlm ソース 1.83 MiB のコーパス、5 試行、中央値 ± 標本標準 偏差。かいつまむと:

ツールレベル圧縮 展開圧縮率
lha-lh5-(デフォルト) ~50 ms~40 ms 29.93 %
zip-6(デフォルト) ~62 ms~3 ms 31.01 %
tar(無圧縮) ~80 ms~82 ms 149.55 %
tar.gz-6(デフォルト) ~210 ms~5 ms 24.93 %

覚えておくべき 3 つの観察

  1. 圧縮速度。lhazip(最速、約 22 % リード)と tar.gz(最遅、約 4 倍遅い)の間。「圧縮 して保管」系のワークロード(ビルド成果物の保持、ミ ラーリング)なら、lha は非自明な圧縮器の うちで最も安価で、生ストリームに対して約 3 倍の優位 性を保つ。
  2. 展開速度。ziptar.gz の展開は 1 桁ミリ秒; lha は約 40 ms。ビット・シリアルのハフマ ンループが天井。絶対値はまだ小さく、CDN のネットワー ク RTT ノイズを下回る。CDN から 100 回展開し直すよ うな負荷は、アルゴリズム選択ではなく HTTP レイテンシ に支配される。
  3. 圧縮率。lhadeflate より約 5 ポイント上(1.8 MiB の ソースで 91 KB 増)。これは 1990 年の意図的な割り切 りで、2020 年代のワークステーションで最も小さく圧縮 するのではなく、286 で高速展開することを目標に調整さ れている。

現代アルゴリズムに負ける場面 — 負けない場面

ベンチページの "Deeper reading" セクションがアルゴリズム内部の理由を解説しています。短 い結論:lha は 1990 年の設計で、今日まで変わらず、天井 を決めるのはアルゴリズムであり実装ではない。

4. 現在の位置づけ — 2026 年になぜこのプロジェクトが存在するか

Vendored した jca02266/lha@86094cb のソース は、1995-2003 年の ANSI C コードベースで、2022 年に autotools 化を一回だけ経たものです。ljh-sh/lha はそこ から先、たった一つのことだけをします:あらゆるプ ラットフォーム向けに lha の単一静的バイナリ を提供し、ユーザにコンパイラを要求しない

2026 年、この価値提案に具体的な需要が 3 つあります:

4.1 レガシー .lzh の展開

最も分かりやすいケース:誰かが 1994 年のゲームパッチ、 2ch 系の BBS の旧添付ファイル、または 2000 年代の日本の オープンソース書庫を持っている。現代のツールはどれも .lzh を開けない。x eget use lha を実行すれば、2 秒で ~/.local/bin に届き、 lha x foo.lzh で展開できる。このバイナリが なければ、ユーザはコンパイラを入れ、1990 年代の autoconf パッチを探し、libc が壊していないことを祈ることになる。

4.2 CI アーティファクト / CDN 配布用の単一静的バイナリ

lha はあらゆるソースツリーから単一の .lzh 書庫を ~50–80 ms で生成し、ホストに システム依存を求めません。CI アーティファクトの配布者 (ビルド成果物をダウンロード用にパッケージする人すべて) にとって、これは次のような意味を持ちます:

これは ljh-sh が各プロジェクト横断で採用している「静的 バイナリ配布規約」の中核(kenlm、upxz、そして lha)で す。具体的なパイプラインは ビルド監査を参照。

4.3 x-cmd の zuz モジュール — 直接の動機

本プロジェクトが静的ビルドとして配布されている根本の理 由がこれです。

x-cmdzuz モジュールは書庫ファイルのフォーマット を自動判別し、拡張子に応じて適切なツールで透過的に圧縮 / 展開します。tartar.gztar.bz2tar.xzzip7zrarlha 等に対応します。ただし、1 つのアーキ テクチャ上の鉄則があります:

フォーマット専用のツールを同梱しない。常にシステム インストール済みのバイナリを起動する。

この問題は x-cmd issue #131(2024 年 12 月)に上がりました:ユーザが zuz に LHA/LZH サポートを求めているが、 x-cmd が現状サポートするどの可搬パッケージシステムも lha を提供していない。スレッドは次のよう に進みます:

つまり、zuz ユーザにとっての主な導入経路 は:

x uz foo.lha
# zuz が .lha を検出、PATH に lha がない、
# フォールバック:eget ljh-sh/lha --to ~/.local/bin/lha
# その後:~/.local/bin/lha x foo.lha

Homebrew ではない。apt でもない。各ディストロのパッケー ジでもない。既定の静的インストール — 特権 インストール不要、tap 不要、ビルドチェーン不要、x-cmd サポートのすべてのプラットフォームで動く。このプロジェ クトが存在する理由は、まさにこの「既定の静的インス トール能力」を提供することだけです。

x-cmd ユーザで、lha の入っていない環境で x uz foo.lha を実行したなら、あなたはこの バイナリを使っています。x-cmd を使ったことがなく、単 に .lzh を開きたいだけの場合でも、このバ イナリを使っています — 同じ成果物、同じリリース、 同じ vendored ソース。

4.4 このプロジェクトが「無いもの」

境界を正直に:

5. まとめ

経験則:

気にする軸が…選ぶもの
1994 年の .lzh を開く lha(このバイナリ)
クローズドシステムでの単一静的バイナリ lha(~150 KB、ゼロ依存)
zuz 風の自動判別 lha(ljh-sh/lha から惰性取得)
ロングテール CDN で最小サイズ tar.gz -9 または zstd
マイクロ秒オーダーの展開 lz4 または zstd

このページが存在する理由は、「このバイナリとは何か」 と「なぜ存在するのか」を 1 か所にまとめるため & mdash; 歴史ベンチビルド監査FAQ に分散させないため。