最終更新日時(UTC): 2026年05月18日 04時21分35秒
Akira Takahashi が更新

履歴 編集

class template
<random>

# std::subtract_with_carry_engine(C++11)

    namespace std {
      template <class UIntType, size_t w, size_t s, size_t r>
      class subtract_with_carry_engine;

      using ranlux24_base = …;
      using ranlux48_base = …;
      using ranlux24      = …;
      using ranlux48      = …;
    }

## 概要

`subtract_with_carry_engine`クラスは、キャリー付き減算法による擬似乱数生成エンジンである。

テンプレートパラメータの意味は以下の通り:

- `UIntType`: 生成する符号なし整数の型。標準もしくは拡張の符号なし整数型 (ビット幅が`short`以上`long long`以下) 、または処理系定義のサブセットの符号なし整数型でなければならない。
- `w`: ワードサイズ。`0 < w <= std::numeric_limits<UIntType>::digits` でなければならない。
- `s`: 短いラグ。`0 < s < r` でなければならない。
- `r`: 長いラグ。

キャリー付き減算法は、以下の特徴を持つ：

- メルセンヌ・ツイスターより周期が短い(10171)が軽量。
- シードを系統的に選ぶ (例えばスレッド ID) と、特に初期において生成した値の間に線型の相関 (nearly affine dependence) がみられる。これを避けるには
  - `random_device` 等の非決定論的な乱数をシードとして使う
  - 最初の方の値を捨てる

この生成法は、RANLUX (LUXury RANdom numbers) 法の実装にも使われる。

## メンバ関数

### 構築・シード

名前 | 説明 | 対応バージョン
--- | --- | ---
`(constructor)` | コンストラクタ | C++11
`~subtract_with_carry_engine() = default;` | デストラクタ | C++11
`seed` | シードを設定する | C++11

### 生成

名前 | 説明 | 対応バージョン
--- | --- | ---
`operator()` | 擬似乱数を生成する | C++11
`discard` | 指定した回数だけ擬似乱数を生成し、内部状態を進める | C++11

## 静的メンバ関数

### エンジンの特性

名前 | 説明 | 対応バージョン
--- | --- | ---
`min` | 生成し得る値の最小値を取得する | C++11
`max` | 生成し得る値の最大値を取得する | C++11

## メンバ型

型 | 説明 | 対応バージョン
--- | --- | ---
`result_type` | 擬似乱数生成結果の符号なし整数型 `UIntType`。 | C++11

## メンバ定数

定数 | 説明 | 対応バージョン
--- | --- | ---
`static constexpr size_t word_size` | ワードサイズ。状態シーケンス内での各ワードのビット数。テンプレートパラメータ`w`。 | C++11
`static constexpr size_t short_lag` | 短いラグ。進める要素数。テンプレートパラメータ`s`。 | C++11
`static constexpr size_t long_lag` | 長いラグ。オペランドの値間の距離。テンプレートパラメータ`r`。 | C++11
`static constexpr result_type default_seed` | デフォルトのシード値。`19780503u` | C++11
`static constexpr uint_least32_t default_seed` | デフォルトのシード値。`19780503u` | C++26

## 非メンバ関数

名前 | 説明 | 対応バージョン
--- | --- | ---
`operator==` | 等値比較 | C++11
`operator!=` | 非等値比較 | C++11
`operator<<` | ストリームへの出力 | C++11
`operator>>` | ストリームからの入力 | C++11

## 例

    #include <iostream>
    #include <random>
    #include <cstdint>

    int main()
    {
      std::random_device seed_gen;
      std::uint32_t seed = seed_gen();

      // subtract_with_carry_engineのパラメータ設定済み別名であるranlux24_baseを使用する。
      // ランダムなシードを使用して初期化
      std::ranlux24_base engine(seed);

      for (int i = 0; i < 10; ++i) {
        // 乱数を生成
        std::uint32_t result = engine();

        std::cout << result << std::endl;
      }
    }

### 出力

    5880757
    13095533
    1545433
    15249896
    3512432
    2193500
    7368389
    13589182
    9374747
    13701319

## バージョン

### 言語

- C++11

### 処理系

- Clang:
- GCC: 4.7.2 ✅
- ICC:
- Visual C++: 2010 ✅, 2012 ✅, 2013 ✅, 2015 ✅, 2017 ✅
  - 2008には、`std::tr1::subtract_with_carry`が存在する。

## 参照

- Subtract with carry - Wikipedia
- A New Class of Random Number Generators, George Marsaglia and Arif Zaman, The Annals of Applied Probability, Vol. 1, No. 3, 1991
- M. Matsumoto, et al., Common Defects in Initialization of Pseudorandom Number Generators, ACM Trans. Model. Comput. Simul. 17, 15 (2007)
- LWG Issue 3809. Is `std::subtract_with_carry_engine<uint16_t>` supposed to work?
- P4037R1 Supporting `signed char` and `unsigned char` in random number generation
  - `UIntType`テンプレートパラメータの要件が明文化された（拡張符号なし整数型および処理系定義のサブセットを許容）。この仕様はC++26から導入されたが、仕様の欠陥を修正したものであるためコンパイラは早期に対応している場合がある