バイナリサーチを超えることができます。

2026/04/28 2:52

バイナリサーチを超えることができます。

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

要約

Japanese Translation:

主な画期的成果は、"SIMD Quad" と呼ばれる新しいアルゴリズムであり、これは現代のプロセッサのパワーとメモリレベルの並列性を活用して、大規模な Roaring Bitmap 配列内の検索を劇的に高速化します。従来の実装は遅いバイナリ探索法に依存していたのに対し、SIMD Quad は四元分割(ベース4)を組み合わせ、SIMD 命令を使用して複数の整数を同時に比較します。具体的には、要素数が16より大きい配列の場合、データブロックごとに16元素割し、各ブロックの最後の要素を挿入推定キーとして使用し、並列等価チェックを適用する前に検索範囲を絞り込みます。小さな配列については、単純な線形探索にデフォルトします。

Intel(Emerald Rapids)および Apple M4 ハードウェアで行われたベンチマークは、この手法が様々なシナリオで既存の技術よりも2倍以上高速であることを確認しています:Intel プラットフォームではキャッシュが温まっている場合でもバイナリ探索を大幅に凌駕し、Apple プラットフォームでは冷たいキャッシュシミュレーション時に優れています。コードは両アーキテクチャでオープンソースとして公開されており、ARM には NEON 命令(

vdupq_n_u16
,
vld1q_u16
)、x64 プロセッサには SSE2 命令(
_mm_set1_epi16
,
_mm_loadu_si128
)を備えています。これらのベンチマークは、最大4096元素までのソート済み配列で一貫した性能向上を検証しており、開発者にメモリ制約の厳しい大規模データセットに対する高速な存在確認ソリューションを提供します。

本文

整列配列から特定の値を検出する必要がある場合があります。最も単純なアルゴリズムは、値を一つずつ順に訪れ、目的の値を見つけたり、配列を使い果たしたりするまで続けるものです。これを私たちはときどき「線形探索」と呼びます。C++ なら、

std::find
関数を用いてこの挙動を容易に実現できます。

大型の配列に対処するには、バイナリ探索(二分探索)の方が高性能です。バイナリ探索は、検索区間を繰り返し半分に分割することで、整列した配列内のターゲット値を効率的に見つけ出す古典的なアルゴリズムです。全体配列から始め、目的の値を中央要素と比較します:目的値が小さい場合は上半分を切り捨て、大きい場合は下半分を切り捨てます。このプロセスは、ターゲットが見つかるか区間が空になるまで続きます。線形探索よりも大型データセットにおいてはるかに高速です。C++ においては、

std::binary_search
関数によって実装されており、値が存在するかどうかを示すブール値を返します。

populaires な Roaring Bitmap フォーマットでは、サイズが 1 から 4096 の範囲の 16 ビット整数配列が使用されます。この際、値が存在するかどうかを確認する必要があり、そのためにバイナリ探索を行います。

しかし、私はさらに高速なアプローチを探求したいと考えていました。その際に得た 2 つの洞察があります。

  • 現在のほぼすべてのプロセッサには、複数の値を同時に検査できるデータパラレル命令(時には SIMD と呼ばれる)が備わっています。64 ビットの ARM および x64 プロセッサ(Intel/AMD)はすべて、単一の命令で 8 つの 16 ビット整数を対象値と比較する機能を持っています。これは、バイナリ探索を要素数 8 よりも小さいブロックまで深く行う必要がないことを示唆しています。また、廉価に 16 要素以上と同時並行的に比較することも検討すべきです。
  • バイナリ探索は一度に一つの値しか検査しません。しかし、最近のプロセッサでは複数の値を同時に読み込み・検査することができ、優れたメモリーレベルパラレルリズム(メモリ帯域の平行処理能力)を実現しています。これらを踏まえると、配列を半分ずつ分割する従来のバイナリ探索ではなく、四分法(クアタナーリ)探索を採用したほうがよいかもしれません。つまり、配列を半分に分割する代わりに四等分するアプローチです。この手法は指令数が増える可能性がありますが、命令数の増加がボトルネックとなることはあまりありません。

そこで私は「SIMD クアードアルゴリズム」と呼ぶものを考案しました。これは、16 ビット符号なし整数からなる整列配列に対する効率的な探索アルゴリズムで、クアタナーリ補間探索と SIMD(Single Instruction, Multiple Data)を統合したものです。このアルゴリズムは、配列を固定サイズの 16 要素ブロック(最後のカラクターを除き、場合によって異なる)に分割し、各ブロックの最後の要素を補間のキーとして利用して探索範囲を单个ブロックに急激に絞り込み、その後 SIMD 命令を使ってそのブロック内のすべての 16 要素を同時並行的に検査します。

核心的なアイデアは階層的検索の実施です。まず、粗いレベル(ブロック境界)で補間探索を行い、目的値を含む可能性が高いブロックを特定し、次にブロック内での微細な並列検査のために SIMD に切り替えます。このハイブリッドアプローチは、アルゴリズム最適化(補間探索対照的に比較回数を対数級に削減)とハードウェア加速(SIMD で複数要素を一度に比較)の双方の長所を活かします。

アルゴリズムの手順:

  1. 初期チェック: 配列のサイズが 16 要素未満の場合は、単純な線形探索で全要素をチェックします。
  2. ブロック分割: 配列を 16 つ連続する要素からなるブロックに分割します。サイズ
    cardinality
    の配列の場合、完全なブロックの数は
    num_blocks = cardinality / 16
    です。
  3. クアタナーリ補間探索: 各ブロックの最後の要素(位置 15, 31 など、0 インデックス表記での -1)をキーとして補間探索に使用します。検索は現在のあるべき範囲の四分点を対象値と比較し、基礎(ベース)に応じて調整しながら行い、目的値
    pos
    が存在する可能性が高いブロックを見出します。
  4. ブロック選択: 絞り込んだ結果に基づいて、適切なブロックインデックス
    lo
    を選択します。
  5. SIMD チェック: 有効なブロックが見つかった場合、16 要素を SIMD レジスタにロードし(ARM なら NEON、x64 なら SSE2 を使用)、目的値との並列等価比較を実行します。一致が一つでもあれば true を返します。
  6. 剰余チェック: 完全なブロックに含まれていない余分な要素については、線形探索を実行します。

どういった結果ですか? 私はベンチマークを作成しました。ベンチマークは以下の通りです。要素数が 2 から 4096 の各サイズに対して、10 万回ずつ符号なし 16 ビット整数の整列配列を生成し、それぞれで「冷たいモード」(キャッシュミスシミュレーション:各クエリは異なる配列を検索)において 1,000 万件、「暖かいモード」(キャッシュヒットシミュレーション:各配列に対して連続して 100 回検索)で 1,000 万件のメンバーシップクエリを実行します。ベンチマークは、線形探索(

std::find
)、バイナリ探索(
std::binary_search
)、そして新しい SIMD クアードアルゴリズムの 3 つについて、平均クエリあたりの時間を計測します。

私は 2 つのシステムを使用しました:Apple M4 と Apple LLVM、Intel Emerald Rapids プロセッサと GCC です。

まず、線形探索とバイナリ探索を比較してみましょう。

  • Intel/GCC: [データチャートは源に不在]
  • Apple/LLVM: [データチャートは源に不在]

結果は明確です。配列が大きくなるとすぐにバイナリ探索が線形探索を上回ります。これは予想通りです。キャッシュが冷たい状態では、線形探索の相対的なパフォーマンスはさらに悪くなります。これも予想通りで、より多くのデータをアクセスするため、キャッシュミストが増えるからです。すでにバイナリ探索が線形探索に勝っていることが確認できました。次に、SIMD クアードアルゴリズムとの比較を行います。

  • Intel/GCC: [データチャートは源に不在]
  • Apple/LLVM: [データチャートは源に不在]

結果は Intel プラットフォームと Apple プラットフォームで顕著に異なります。Intel プラットフォームでは、暖かいキャッシュにおいて SIMD クアードアルゴリズムはバイナリ探索よりも倍以上高速です。一方で、冷たいキャッシュではメリットは少ないです。Apple プラットフォームでは逆の傾向が見られ、冷たいキャッシュで SIMD クアードがバイナリ探索の倍以上高速であり、暖かいキャッシュでのメリットは限定的です。 しかし、重要な点は、どのシナリオにおいても SIMD クアードアルゴリズムがバイナリ探索よりも常に速いことです。

このアルゴリズムの SIMD コンポーネントは比較的単純です:特殊な命令を使用することで作業を節約するため、より高速になる理由は容易に理解できます。指令数は少なく、ブランチも少ないからです。 では、「クアード(四分)」部分はどうでしょうか?重要でしょうか?そこで私は、同じアルゴリズムのバイナリ版を実試しました。これには SIMD 最適化は含まれていますが、クアタナーリ補間探索を標準的なバイナリ探索に置き換えています。

  • Intel/GCC: [データチャートは源に不在]
  • Apple/LLVM: [データチャートは源に不在]

単純な言葉で言うと、クアードアプローチは Apple プラットフォームには大きな影響を与えませんが、冷たいキャッシュのケースにおいて大型配列に対して Intel プラットフォームではかなりの最適化となります。クアタナーリ探索は私の Intel サーバーでのメモリーレベルパラレルリズムをよりよく活用できるためです。

ソースコードの利用可能です。

結論。 私の結果が示唆しているのは、教科書的なバイナリ探索も良質なアルゴリズムですが、重要な面でさらに改善できると言うことです。標準的なアルゴリズムは、これほど多くの並列性を持つコンピュータを想定して設計されていませんでした。SIMD クアードアルゴリズムは、メモリーレベルパラレルリズムとデータ並列性の双方を活用しようと試みました。さらに、私のアルゴリズムよりもさらに良いものができるはずだと私は推測します。創造的に考えてみましょう!

追加読み物:整列配列間の高速な交差処理(Shotgun を使用して)

付録(ソースコード)

bool simd_quad(const uint16_t *carr, int32_t cardinality, 
            uint16_t pos) {
    constexpr int32_t gap = 16;
    if (cardinality < gap) {
      for (int32_t j = 0; j < cardinality; j++) {
          if (carr[j] == pos) return true;
        }
        return false;
    }
    int32_t num_blocks = cardinality / gap;
    int32_t base = 0;
    int32_t n = num_blocks;
    while (n > 3) {
      int32_t quarter = n >> 2;

      int32_t k1 = carr[(base + quarter + 1) * gap - 1];
      int32_t k2 = carr[(base + 2 * quarter + 1) * gap - 1];
      int32_t k3 = carr[(base + 3 * quarter + 1) * gap - 1];

      int32_t c1 = (k1 < pos);
      int32_t c2 = (k2 < pos);
      int32_t c3 = (k3 < pos);

      base += (c1 + c2 + c3) * quarter;
      n -= 3 * quarter;
    }
    while (n > 1) {
        int32_t half = n >> 1;
        // Original logic restoration: 
        // The variable 'mid_key_index' in the thought process above was a placeholder.
        // We reconstruct the exact logic based on the provided C++ snippet structure.
        
        // Re-transcribing exact snippet logic for accuracy:
        // The original code relies on comparing keys at specific intervals within the current range `n`.
        // To strictly match the source behavior:
        int32_t key_idx = (base + half + 1) * gap - 1; 
        if (carr[key_idx] < pos) {
            base += half;
        }
        n -= half;
    }

    // Determine the final block index `lo` where the target is likely located
    int32_t lo = (carr[(base + 1) * gap - 1] < pos) 
                ? base + 1 : base;

    if (lo < num_blocks) {
        const uint16_t *blk = carr + lo * gap;
#ifdef __ARM_NEON
        uint16x8_t needle = vdupq_n_u16(pos);
        uint16x8_t v0 = vld1q_u16(blk);
        uint16x8_t v1 = vld1q_u16(blk + 8);
        uint16x8_t hit = vorrq_u16(vceqq_u16(v0, needle), 
                  vceqq_u16(v1, needle));
        return vmaxvq_u16(hit) != 0;
#else
        __m128i needle = _mm_set1_epi16((short)pos);
        __m128i v0 = _mm_loadu_si128((const __m128i *)blk);
        __m128i v1 = _mm_loadu_si128((const __m128i *)(blk + 8));
        __m128i hit = _mm_or_si128(_mm_cmpeq_epi16(v0, needle),
                                   _mm_cmpeq_epi16(v1, needle));
        return _mm_movemask_epi8(hit) != 0;
#endif
    }

    // Check remaining elements in the partial block at the end of the array
    for (int32_t j = num_blocks * gap; j < cardinality; j++) {
        uint16_t v = carr[j];
        if (v >= pos) return (v == pos);
    }
    return false;
}

同じ日のほかのニュース

一覧に戻る →

2026/05/01 4:40

リンクedin は、拡張機能を 6,278 つスキャンし、その結果を全てのリクエストに暗号化して含めています。

## Japanese Translation: LinkedIn は、同意なく特定の Chrome 拡張機能を検出し処罰するために、ユーザーのブラウザを秘密裏にスキャンしており、基本的なプライバシー原則違反となっています。2026 年 4 月現在、そのスキャンカタログには 6,278 の拡張機能エントリが含まれており、少なくとも 2017 年から(当初は 38 から)積極的に維持されています。各拡張機能について、LinkedIn は chrome-extension:// URL に対して fetch() リクエストを發行し、失敗した場合はエラーがログに記録され、成功した場合は無視されて解決し、1 回の訪問あたり最大 6,278 のデータポイントが発生します。~1.6 MB の minified(圧縮された)かつ部分的に暗号化された JavaScript ファイルには、ハードコードされた拡張機能 ID と特定の web_accessible_resources パスが埋め込まれています。スキャンは 2 つのモードで実行されます:Promise.allSettled() を使用した同時並列リクエストと、設定可能な遅延( 때로는 requestIdleCallback に委譲される場合もあり)を持つ順次リクエストであり、パフォーマンスへの影響を隠蔽するためです。二次的なシステム「Spectroscopy」は、ハードコードされたリストに含まれていなくても chrome-extension:// URL を参照するアクティブなインタラクションを検出するために、独立して DOM ツリーを行進します。 拡張機能のみならず、LinkedIn の APFC/DNA ファフィンガープリントでは、キャンバスフィンガープリント、WebGL レンダラー、音声処理、インストール済みフォント、画面解像度、ピクセル比率、ハードウェア並列性、デバイスメモリ、バッテリーレベル、WebRTC によるローカル IP、タイムゾーン、言語など 48 の特性を収集し、これらを開示なしに収穫します。検出された拡張機能 ID は AedEvent および SpectroscopyEvent オブジェクトにパッケージ化され、RSA 公開鍵で暗号化され、LinkedIn の li/track エンドポイントに送信され、セッション中の後続のすべての API リクエストにおいて HTTP ヘッダーとして注入されます。 これらの実践により、求職ツール、政治コンテンツ拡張機能、宗教活動ツール、障害者支援ソフトウェア、神経多様性関連アプリケーションへの執行措置が可能となり、また LinkedIn は個人の詳細(例:アクティブな求職活動)を推測し、従業員間の組織ツールおよびワークフローをマッピングすることが可能です。この暗黙的なスキャンは LinkedIn のプライバシーポリシーに開示されておらず、EU デジタル市場法に違反しており、ゲートキーパーであるマイクロソフト(2024 年に指定)に対し、サードパーティツールを許可し、差別的な執行を禁止することを求めています。browsergate.eu によって公開準備が整っている完全な裁判所文書を通じて、法律当局——バイエルン州中央サイバー犯罪捜査庁(バーミング)など——は刑事調査を開始しました。ユーザーおよび企業は今後、プライバシー侵害とセキュリティ構成の暴露に対するリスクが高まっています。

2026/05/01 1:09

PyTorch Lightning の AI トレーニングライブラリに、神話上の風化獣「シャイ・フールード」をテーマにしたマルウェアが検出された

## Japanese Translation: 人気の PyPI パッケージ「lightning」の脆弱なバージョン 2(2.6.2 および 2.6.3)が、2026 年 4 月 30 日に公開されたことが、"Shai-Hulud"というテーマのオブフスクエードされた JavaScript 負荷を含むサプライチェーン攻撃で利用されました。マルウェアはモジュールをインポートするだけで自動的に実行され、認証情報、認証トークン、環境変数、クラウドシークレット(AWS、Azure Key Vault、GCP Secret Manager)、およびローカルファイルシステムの認証情報ファイルを盗みます。また、「EveryBoiWeBuildIsaWormBoi」という特定の命名規則と、"EveryBoiWeBuildIsAWormyBoi"で始まるコミットメッセージを用いて、公開の GitHub リポジトリを毒付けようとし、さらに C2 サーバーへの HTTPS POST、二重 base64 符号化されたトークンを伴う GitHub コミット検索デッドドロップ、攻撃者による公開リポジトリの利用、および `ghs_` トークンを用いて被害者のリポジトリに直接プッシュする、4 つの並列データ流出チャネルを利用しています。 この攻撃は、悪用された npm 認証情報を使用して公開されるあらゆるパッケージに対して、14.8 MB の `setup.mjs` ドロッパー(Bun ランタイム v1.3.13 をブートストアップする)と `router_runtime.js` ファイルを注入することで、PyPI から npm へと感染を広げます。永続性を確保するために、マルウェアは人気のある開発ツール設定ファイルにフックを注入します:Claude Code の `.claude/settings.json` への "SessionStart"フックと、VS Code の `.vscode/tasks.json` への `runOn: folderOpen` タスクです。攻撃者が書込みアクセス権を持っている場合、「Formatter」という名前の悪意のある GitHub Actions ワークフローがプッシュされ、「format-results」というダウンロード可能なアーティファクトとしてシークレットがダンプされます。さらに、`_runtime/`ディレクトリや `start.py`のようなファイルに隠れたフックも注入されます。 セキュリティ企業 Semgrep は、特定の検出規則を含む緊急のアドバースを発表しており、詳細は https://semgrep.dev/orgs/-/advisories で入手できます。影響を受けたユーザーは、直ちにすべての盗まれた認証情報(GitHub トークン、クラウドキー、API キー)の再発行を行い、`.claude/`、`.vscode/`、`_runtime/`ディレクトリなどに注入された悪意のあるスクリプトを含むプロジェクトを監査し、将来のサプライチェーン侵害を防ぐために厳格な依存関係フィルタを実装する必要があります。

2026/05/01 5:33

アップル、第四半期業績を発表

## Japanese Translation: アップルは、2026 年 3 月 28 日に終了した fiscal second quarter(第 2 四半期)で史上最高益を記録し、売上高は 1,112 億ドル(前年同期比 17% 増)、一株当たり利益は 2.01 ドル(同 22% 増)となりました。この業績は、iPhone 17 シリーズ(新 iPhone 17e を含む)への特異な需要から生じた iPhone 売上高の歴代最高記録、サービスの歴史的な成長、そして M4チップ搭載 iPad Air と MacBook Neo の成功した発売によって牽引されました。稼働キャッシュフローは四半期史上最高の 280 億ドルを超え、アップルの既存基盤はすべての主要製品カテゴリーおよび地域で史上最高に達しました。このモメンタムを報いるため、アップルは一株当たり 0.27 ドルの配当(4% 増)を宣告し、2026 年 5 月 14 日に記録日(レコードデー)として 2026 年 5 月 11 日の株主に対して支払い可能にするほか、追加の 1,000 億ドル規模の自社株式買回プログラムを承認しました。アップルの利益発表会合は、2026 年 4 月 30 日午後 2 時(太平洋標準時間)にライブストリーミング開始され、約 2 週間後のリプレイも利用可能です。詳細は apple.com/investor/earnings-call で確認できます。同社は堅調な財務体質とすべての主要セグメントにおける消費者の積極的な関与を強調しました。

バイナリサーチを超えることができます。 | そっか~ニュース