MathRand()はどのように値を生成するのですか? - ページ 2

 
yu-sha さん。

MathRand()が値を取得する方法を教えてください。

MathRand()は、宣言した範囲内で均等になることを期待できますか?

もちろん、もっと複雑なアルゴリズムもあります。

ソース rand.c :

/***
*rand.c - random number generator
*
*       Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
*
*Purpose:
*       defines rand(), srand() - random number generator
*
*******************************************************************************/

#include <cruntime.h>
#include <mtdll.h>
#include <stddef.h>
#include <stdlib.h>

#ifndef _MT
static long holdrand = 1 L;
#endif  /* _MT */

/***
*void srand(seed) - seed the random number generator
*
*Purpose:
*       Seeds the random number generator with the int given.  Adapted from the
*       BASIC random number generator.
*
*Entry:
*       unsigned seed - seed to seed rand # generator with
*
*Exit:
*       None.
*
*Exceptions:
*
*******************************************************************************/

void __cdecl srand (
       unsigned int seed
       )
{
#ifdef _MT

       _getptd()->_holdrand = (unsigned long)seed;

#else  /* _MT */
       holdrand = (long)seed;
#endif  /* _MT */
}


/***
*int rand() - returns a random number
*
*Purpose:
*       returns a pseudo-random number 0 through 32767.
*
*Entry:
*       None.
*
*Exit:
*       Returns a pseudo-random number 0 through 32767.
*
*Exceptions:
*
*******************************************************************************/

int __cdecl rand (
       void
       )
{
#ifdef _MT

       _ptiddata ptd = _getptd();

       return( ((ptd->_holdrand = ptd->_holdrand * 214013 L
           + 2531011 L) >> 16) & 0x7fff );

#else  /* _MT */
       return(((holdrand = holdrand * 214013 L + 2531011 L) >> 16) & 0x7fff);
#endif  /* _MT */
}
 

0から任意の値までの数値IntでRNG機能が必要です。

Intの最大値=2,147,483,647なので、その値まで計算 する。

この関数を取得しました。分布は一様 だと思います。

int RandomInteger(int max_vl){//случайное Int от 0 до  Max Int
        //srand(0);//если нужна повторяемость.  MathSrand(GetTickCount()) если нужна неповторяемость
        int r=MathRand();// от 0 до 32767.
        double k=32767.0;
        if(max_vl>32767){
                r=r+MathRand()*32767;//0...32767 + 0.. 32767*32767(с шагом 32767)  max=1073709056 > 1 mlrd
                k=k*k;
                if(max_vl>1073709056){// int type max alue =2 147 483 647 > 2 mlrd
                        r=r*2+MathRand()%2;//0...2 147 483 647 > to max int number c шагом 2 + (0 или 1)
                        k=k*2;
                }
        }
        return (int)MathFloor(r/k*max_vl);
}
 
記事には4294967295への ジェネレーターがあります。
 
Rorschach:
記事には4294967295までの ジェネレーターがあります。

Alglib SBは高精度な発振器を搭載しています

UPD: https://www.mql5.com/ru/forum/324066#comment_13500222 試してみました。

 
Rorschach:
記事には4294967295への ジェネレーターがあります。

ありがとうございます。計算速度で比較してみました。
標準的なrand()の私の関数では、2倍も遅いことが判明しました。もっとシンプルなコードに見えたのに...。


 
Igor Makanu:

Alglibの高精度ジェネレータがある

UPD: https://www.mql5.com/ru/forum/324066#comment_13500222 試してみました。

見たけど、alglib抜きで欲しい。さらに、その関数には多くの*/%があります。明らかに遅いので、速度の比較はしていません。 記事中のジェネレータはビットシフトで動作します。その方が高速です。

 

速度を最適化するために関数を書き直しました。

int RandomInteger(int max_vl){return (int)MathFloor((MathRand()+MathRand()*32767.0)/1073741824.0*max_vl);}//случайное Int от 0 до  Max Int
その結果、分布は一様であることが判明しました。実験の画像はブログでご覧くださいhttps://www.mql5.com/ru/blogs/post/735953

記事からRMSを書き直しました。
不要なものを捨てたら、こうなった。

//если из define переместить в код RNDUint, то скорость работы увеличится на 30% для 10 млн повторов с 600 мс до 850 мс
#define  xor32  xx=xx^(xx<<13);xx=xx^(xx>>17);xx=xx^(xx<<5)
#define  xor128 t=(x^(x<<11));x=y;y=z;z=w;w=(w^(w>>19))^(t^(t>>8))
#define  inidat x=123456789;y=362436069;z=521288629;w=88675123;xx=2463534242

class RNDUint{
protected:
   uint      x,y,z,w,xx,t;
public:
        RNDUint(void){inidat;};
        ~RNDUint(void){};
   uint      Rand()    {xor128;return(w);};//равномерное распределение на отрезке [0,UINT_MAX=4294967295].
   double    Rand_01() {xor128;return((double)w/UINT_MAX);};//равномерное распределение на отрезке [0,1].
   void      Reset()   {inidat;};//сброс всех исходных значений в первоначальное состояние.
   void      SRand(uint seed)  {//установка новых исходных значений генератора.seed= [0,UINT_MAX=4294967295]. При seed=0 функция меняет начальные значения случайным образом.
      int i;if(seed!=0){xx=seed;}for(i=0;i<16;i++){xor32;}xor32;x=xx;xor32;y=xx;xor32;z=xx;xor32;w=xx;for(i=0;i<16;i++){xor128;}
   };
};

分配も平等であることがわかりました。

記事のオリジナルと単純なMathRand()の両方の関数の速度を比較してみました。


記事rnd.Rand_01()の元のもの - 602 ms.
rnu.Rand_01()の記事による短縮版 - 596 ms
RandomInteger()の最適化バージョン - 840 ms (旧バージョン 1200 ms, すなわち 25% 高速化)
MathRand()だけで-353ms(最速ですが、分布にばらつきが出ます。必要な数値の範囲が32767より大きい場合、結果はスキップされます。32767より小さい場合、例えばi=3111.のような場合、丸めの頻度が高くなる点がある)。

活用する)
Rand 0 ... Max Int с равномерным распределением
Rand 0 ... Max Int с равномерным распределением
  • www.mql5.com
Потребовалась функция ГСЧ с гнерацией числа Int от 0 до любого значения.Получилась такая функция. Думаю распределение получилось равномерным. int RandomInteger(int max_vl){return
 
elibrarius:
面白いですね。標準ライブラリに別のランダムを 見つけましたが、より良いとは思えません。
 

なぜ、そこまで複雑にするのか?

このようにできます(大雑把ですが)。

if (MathRand()%100>50) => Buy

if (MathRand()%100<50) => Sell

また、遊んでみたい、何を表示しているのか見てみたいという場合は、このようにすることができます。

int x=1;

if (MathRand()%100>50) x=1;

if (MathRand()%100<50) x=2;

Comment(x);

を実行し、値がどのように変化するかを確認します。

 
elibrarius:

速度を最適化するために、関数を書き直しました。

分布は均一である。実験の画像はブログでご覧くださいhttps://www.mql5.com/ru/blogs/post/735953

記事からRNGを書き換えてみました。
不要なものを捨てたら、こうなった。

分布も一様であることがわかります。

ヘルプのディストリビューションと比較してみましたが、特に違いは見当たりません

ファイル: