インテル® C++ コンパイラー 18.0 デベロッパー・ガイドおよびリファレンス

使用モデル

ショートベクトル乱数ジェネレーター (SVRNG) ライブラリーの典型的な使用モデルは、標準 C++ やインテル® マス・カーネル・ライブラリー (インテル® MKL) のベクトル統計乱数ジェネレーターと同じです。

Windows* では、スタティック/ダイナミック・ライブラリーを明示的にリンクする必要があります (スタティック: libirng.lib、ダイナミック: libirngmd.lib)。Linux* および macOS* では、コンパイラー・ドライバーにより自動的にリンクされます。

次の例は、シード 777 で基本ジェネレーター・エンジン MT19937 を使用してランダム・ストリームの生成をします。このエンジンは 2 つの配列を生成します。1 つ目は、<a = 0.0、b = 4.0> の範囲の 1024 個の一様分布乱数で、コンパイラーによりベクトル化されるスカラー・ジェネレーター呼び出しによって生成されます。2 つ目は、16 要素のブロックから成る、引数 <平均 = 2.0、標準偏差 = 1.0> の 1024 個の正規分布乱数で、SIMD ベクトル実装の直接呼び出しによって生成されます。生成後、エンジンと分布を削除します。そして、エラーの有無を調べるため、ステータスをチェックします。この例は、指定した引数で 2 つの分布のサンプルの平均を計算することを目的としています。

#include <stdio.h>
#include <svrng.h>

int main( void )
{
  int                   i, st = SVRNG_STATUS_OK;
  double                res1[1024],  res2[1024];
  double                sum1 = 0, sum2 = 0;
  double                mean1, mean2;
  svrng_engine_t        engine;
  svrng_distribution_t  distr1, distr2;

    /* mt19937 エンジンを作成 */
    engine = svrng_new_mt19937_engine( 777 );

    /* 一様分布を作成 */
    distr1 = svrng_new_uniform_distribution_double( 0.0, 4.0 );

    /* 正規分布を作成 */
    distr2 = svrng_new_normal_distribution_double( 2.0, 1.0 );

    /* スカラー・ジェネレーター呼び出し、コンパイラーによりベクトル化される */
    #pragma ivdep
    #pragma vector always
    for( i = 0; i < 1024; i ++ ) {
        res1[i] = svrng_generate_double( engine, distr1 );
    }

    /* SIMD ベクトル実装の直接呼び出し */
    /* 16 パックド要素を生成 */
    for( i = 0; i < 1024; i += 16 ) {
        *((svrng_double16_t*)(&res2[i])) = 
        svrng_generate16_double( engine, distr2 );
    }

    /* 平均値を計算 */
    for( i = 0; i < 1024; i++ ) {
        sum1 += res1[i];
        sum2 += res2[i];
    }

    mean1 = sum1 / 1024.0;
    mean2 = sum2 / 1024.0;

    /* 結果を出力 */
    printf( "Sample mean of uniform distribution = %f\n", mean1 );
    printf( "Sample mean of normal  distribution = %f\n", mean2 );

    /*ステータスをチェック */
    st = svrng_get_status();

    if(st != SVRNG_STATUS_OK) {
        printf("FAILED: status error %d returned\n", st);
    }

    /* 分布を削除 */    
    svrng_delete_distribution( distr1 );
    svrng_delete_distribution( distr2 );

    /* エンジンを削除 */
    svrng_delete_engine( engine );

return st;
}

もう 1 つの例は、特定のエンジンで並列およびシーケンシャルに生成した場合に同じ乱数シーケンスの生成を保証する、"Skip-Ahead" 法を使用するアプローチを示します。rand0 エンジンを作成し、"Skip-Ahead" 法を利用して T スレッドにコピーします。各スレッドは、一様分布の符号なし整数型の乱数を N 個生成し、すべての乱数 (LEN=T*N) をシーケンシャル呼び出しと比較します。

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

#define LEN        1024
#define T          8
#define N          (LEN/T)

int main( void ) {
  uint32_t       seq_res[LEN+32], parallel_res[LEN+32];
  svrng_engine_t seq_engine;
  svrng_engine_t parallel_engine[T];
  int            l, n, t, errs = 0, st = SVRNG_STATUS_OK;

    /* シーケンシャル・エンジンと分布を作成 */
    seq_engine = svrng_new_rand0_engine( 777 );

    /* "Skip-Ahead" 法 を使用して t*N オフセットで */
    /* 既存のシーケンシャル・エンジンを新しい T 並列エンジンにコピー */
    for( t = 0; t < T; t++ ) { 
        int thr_offset = t*N;
        parallel_engine[t] = svrng_copy_engine( seq_engine );
        parallel_engine[t] = \
          svrng_skipahead_engine( parallel_engine[t], thr_offset );
    }

    /* スカラー関数を使用するシーケンシャル・ループ (ベクトル化可能) */
    #pragma ivdep
    #pragma vector always
    for( l = 0; l < LEN; l++ ) {
        seq_res[l] = svrng_generate_uint( seq_engine );
    }

    /* SIMD ベクトル関数を使用する並列ループ */ 
    /* 複数のスレッドに分配可能 */
    for( t = 0; t < T; t++ ) {
        for( n = 0; n < N; n += 8 ) {
            *((svrng_uint8_t*)(&(parallel_res[t*N+n]))) = \
            svrng_generate8_uint( parallel_engine[t] );
        } 
    }

    /* シーケンシャルと並列の結果を比較 */
    for(l = 0; l < LEN; l++) {
        if( parallel_res[l] != seq_res[l]) {
            errs++;
        }
    }

    /* ステータスをチェック */
    st = svrng_get_status();

    /* 全体の結果を出力 */
    if(st != SVRNG_STATUS_OK) {
        printf("FAILED: status error %d returned\n", st);
    }
    else if(errs) {
        printf("FAILED: %d skipahead errors\n",  errs);
    }
    else {
        printf("PASSED\n");
    }

    /* エンジンを削除 */
    svrng_delete_engine( seq_engine );
    for( t = 0; t < T; t++ ) {
        svrng_delete_engine(parallel_engine[t]);
    }

  return (errs-st);
}