乱数と浮動小数点 - 1 / 3 -
BREW の乱数
BREW では、現在の CDMA 時刻( 携帯電話内蔵時計の時刻 )をシードとして乱数を発生させます。しかし、任意の値をシードとして乱数を発生させる方法は BREW 標準で用意されていませんので、独自に実装する必要があります。
関連情報:" Wikipedia : 乱数列 "
関連情報:" Wikipedia : 擬似乱数 "
アプリの概要
- 最初に、メニューを表示します。
- 「1」キーが押されると、GETRAND 関数による乱数を表示します。
- 「2」キーが押されると、ISource インターフェースによる乱数を表示します。
- 「3」キーが押されると、sin 関数を 15°刻みで表示します。
乱数の取得方法
BREW では、GETRAND 関数または ISource インターフェースを使って乱数を発生させます。
■長さ 16 の byte (unsigned char) 型の乱数を発生させる方法
byte bytes[16]; GETRAND(bytes, 16);
■乱数列にならないコード
GETRAND 関数によって生成される乱数列の初項を並べても乱数列になりません。また、GETRAND 関数を呼び出す分だけ時間がかかるので、効率的とも言えません。
// 下記コードによって生成される配列 bytes[] は乱数列ではない。 byte bytes[16]; int i; for (i = 0; i < 16; i++) { GETRAND(bytes + i, 1); }
■ISource インターフェースによる乱数
ClassID " AEECLSID_RANDOM " を使って ISource インスタンスを作成し、ISOURCE_Read 関数から乱数列を取得できます。
// ISource インターフェースを使った乱数列の生成 static void GetRandByISourceAndWrite(MathApp* app) { byte bytes[16]; char buf[80]; ISource* random; int i; random = NULL; ISHELL_CreateInstance(app->a.m_pIShell, AEECLSID_RANDOM, (void**)&random); ISOURCE_Read(random, (char*)bytes, 16); ISOURCE_Release(random); COMMON_WriteString(&app->common, "got random bytes by using ISource.\n"); for (i = 0; i < 16; i++) { SPRINTF(buf, "index %2d: %d\n", i, bytes[i]); COMMON_WriteString(&app->common, buf); } return; }
乱数の性質
BREW の乱数列の発生アルゴリズムは、ドキュメントには記載されていません。エミュレータと携帯端末では乱数の実装方法が異なることを弊社では確認しています。
実際に調べてみると、エミュレータ上では乱数の分布に偏りがあります。
■エミュレータでの長さ 5000 の乱数列の分布
0 から 255 までの区間を等間隔に四つに分割する形で、値の出現回数に偏りがあります。
しかし、携帯電話実機ではこのような乱数の分布の偏りは現れません。
シードの設定ができないので、BREW の乱数には再現性がありません。( シードが設定できる乱数は、独自に実装しなければいけません。 )