mql5 언어의 특징, 미묘함 및 작업 방법 - 페이지 136

 
Nikolai Semko :
저것들. 침대 밑에 굴려진 10센트를 찾기 위해 100달러 지폐에 불을 붙일 준비가 되셨습니까?

동전일 수도 있고 아닐 수도 있습니다.

   srand ( GetTickCount ());
   uint v10 = 0 , v19900 = 0 ;
   for ( uint i = 0 ;  i < UINT_MAX ;  ++ i) {
       int cur = rand ();
       if (cur % 20000   == 10 )
         ++ v10;
       else if (cur % 20000   == 19900 )
         ++ v19900;   
   }
   Alert ( "10 probability = " , ( double )v10/ UINT_MAX * 100 , "%;  1990 probability = " , ( double )v19900/ UINT_MAX * 100 , "%" );
   // Alert: 10 probability = 0.006103515626421085%;  19900 probability = 0.003051757813210543%
        

10번은 확률이 2배입니다. 그리고 가장 중요한 것은 get_rand() 비용에 대한 주장이 허무맹랑하다는 것입니다. 그래서 일반적으로 할 수 있는데 왜 (균일한 분포를 기대하면서) 확률이 이동된 항문을 통해 난수를 얻 습니까? 당신은 100달러 지폐를 저축하는 것이 아니라 일치시킵니다.

 
Vict :

동전일 수도 있고 아닐 수도 있습니다.

10번은 확률이 2배입니다. 그리고 가장 중요한 것은 get_rand() 비용에 대한 주장이 허무맹랑하다는 것입니다. 그래서 일반적으로 할 수 있는데 왜 (균일한 분포를 기대하면서) 확률이 이동된 항문을 통해 난수를 얻 습니까? 당신은 100달러 지폐를 저축하는 것이 아니라 일치시킵니다.

예, 당신의 기능의 강한 느림에 대해 틀렸습니다. 알고리즘을 잘못 이해했습니다. 소리안.
그러나 여전히 내 알고리즘은 더 보편적이고 귀하와 같은 숫자 32767에 의해 제한되지 않는다는 사실에도 불구하고 제안된 모든 알고리즘 중 가장 빠른 것으로 나타났습니다.
증명 코드.

이 스크립트는 임의의 색상과 임의의 좌표를 가진 점 배열을 무작위로 생성합니다. 배열 크기는 그래프 차트의 픽셀 수와 같습니다. 이것을 5회 반복한다.

  1. 표준 rand() 함수 사용
  2. get_rand() 함수 사용
  3. 내 ulong randUlong() 함수로
  4. 내 uint randUint() 함수로
  5. @Alexey Navoykov 의 ulong RandomLong() 함수 사용
 2019.06 . 09 03 : 42 : 25.958 TestSpeedRand (EURGBP,H4)       Время формирования случайных массивов = 9894 микросекунд.  Всего сгенерировано 5203975 случайных чисел rand ()
2019.06 . 09 03 : 42 : 28.010 TestSpeedRand (EURGBP,H4)       Время формирования случайных массивов = 24899 микросекунд. Всего сгенерировано 5203975 случайных чисел get_rand()
2019.06 . 09 03 : 42 : 30.057 TestSpeedRand (EURGBP,H4)       Время формирования случайных массивов = 22172 микросекунд. Всего сгенерировано 5203975 случайных чисел randUlong()
2019.06 . 09 03 : 42 : 32.098 TestSpeedRand (EURGBP,H4)       Время формирования случайных массивов = 16013 микросекунд. Всего сгенерировано 5203975 случайных чисел randUint()
2019.06 . 09 03 : 42 : 34.145 TestSpeedRand (EURGBP,H4)       Время формирования случайных массивов = 25524 микросекунд. Всего сгенерировано 5203975 случайных чисел RandomLong()

숫자는 rand()% 20000을 사용할 때 문제의 본질을 보여 주는 방식으로 선택되었습니다.


그것은해야한다:


 //+------------------------------------------------------------------+
uint get_rand( uint max)
  {
   static bool f= false ;
   if (!f) 
     {
      f= true ;
       srand ( GetTickCount ());
     }
   uint limit=(max+ 1 ) *(( 32767 + 1 )/(max+ 1 ));
   uint val;
   while ((val= rand ())>=limit);
   return val % (max+ 1 );
  }
//+------------------------------------------------------------------+
ulong randUlong( ulong max= ULONG_MAX ){ return ((( ulong ) rand ()<< 60 )|(( ulong ) rand ()<< 45 )|(( ulong ) rand ()<< 30 )|(( ulong ) rand ()<< 15 )|( ulong ) rand ())%max;}
//+------------------------------------------------------------------+
uint randUint( uint max= UINT_MAX ) { return ((( uint ) rand ()<< 30 )|(( uint ) rand ()<< 15 )|( uint ) rand ())%max;}
//+------------------------------------------------------------------+
ulong RandomLong( ulong range)
  {
#define _MAXRND(rang,rnd_range) ((rnd_range) -((rnd_range)-rang)%rang- 1 )
#define _RND ulong ( rand ())
   ulong rnd,max, const bit= 1 ;
   if (range <= bit<< 15 ) { if (!range) return 0 ;  max=_MAXRND(range, 1 << 15 );   while ((rnd=_RND) > max);   return rnd%range; }
   if (range <= bit<< 30 ) { max=_MAXRND(range, bit<< 30 );   while ((rnd=(_RND | _RND<< 15 )) > max);   return rnd%range; }
   if (range <= bit<< 45 ) { max=_MAXRND(range, bit<< 45 );   while ((rnd=(_RND | _RND<< 15 | _RND<< 30 )) > max);   return rnd%range;  }
   if (range <= bit<< 60 ) { max=_MAXRND(range, bit<< 60 );   while ((rnd=(_RND | _RND<< 15 | _RND<< 30 | _RND<< 45 )) > max);   return rnd%range; }
   else   { max=_MAXRND(range,bit<< 64 );   while ((rnd=(_RND|_RND<< 15 |_RND<< 30 |_RND<< 45 |_RND<< 60 ))>max);   return rnd%range; }
#undef _RND
#undef _MAXRND
  }
//+------------------------------------------------------------------+
위협적이지만 99.9%의 경우에 이 기능도 작동합니다.
 uint randUint( uint max) { return ((( uint ) rand ()<< 15 )|( uint ) rand ())%max;}
더 빠르게 실행됩니다.
이 함수는 0에서 1073741824 사이의 임의의 숫자를 생성합니다. 이 숫자는 전체 기록에서 계측기의 틱 수보다 훨씬 큽니다. 그러한 기능의 "부정직"은 작업의 99.9%에 대해 미시적일 것입니다.
파일:
 
Nikolai Semko :

그러나 여전히 내 알고리즘은 더 보편적이고 귀하와 같은 숫자 32767에 의해 제한되지 않는다는 사실에도 불구하고 제안된 모든 알고리즘 중 가장 빠른 것으로 나타났습니다.
증명 코드.

열심히 해주셔서 감사합니다. 정말 흥미로운 결과입니다. rand() 함수가 너무 빨라서 산술 연산 보다 빠르게 작동한다는 것이 밝혀졌습니다.

 
Alexey Navoykov :

열심히 해주셔서 감사합니다. 정말 흥미로운 결과입니다. rand() 함수가 너무 빨라서 산술 연산 보다 빠르게 작동한다는 것이 밝혀졌습니다.

아니, 더 빠르지 않습니다. 2배의 제곱근을 취하는 것과 같은 약 나노초입니다. +-*/ 작업은 나노초 단위로 수행됩니다.
그러나 제곱근과 마찬가지로 rand()는 소프트웨어가 아닌 하드웨어 수준의 최신 프로세서에서 수행됩니다.

 
Nikolai Semko :

아니, 더 빠르지 않다. 2배의 제곱근을 취하는 것과 같은 약 나노초입니다. +-*/ 작업은 나노초 단위로 수행됩니다.
그러나 제곱근과 마찬가지로 rand()는 소프트웨어가 아닌 하드웨어 수준의 최신 프로세서에서 수행됩니다.

그렇다면 왜 그렇지 않습니다. 귀하의 버전은 항상 5개의 rand()를 호출한다는 점에서 내 버전과 다릅니다. 20000 범위에서 평균 1.64번, 범위 256에서 1번. 전체적으로 rand()는 각 반복에 대해 25번 호출됩니다. , 그리고 나는 1.64*2+3 = 5.3배입니다. 일반적으로 이상한 상황은 물론, 그 이유가 정확히 무엇인지 알아낼 필요가 있습니다. 당신은 또한 많은 비트 연산을 추가로 수행했습니다 ...

 
Nikolai Semko :

1. 글쎄, 우리는 당신의 기능에서 문제가 해결되지 않고 위장 만하면 체중을 줄이지 않고 벨트를 더 단단히 조이는 것을 이해합니다.

2. Alexey 옵션에서 이것은 최악의 옵션입니다. 다른 많은 상황에서 속도는 거의 랜드() 수준이지만 시간은 일정합니다.

3. 왜 rand()가 그렇게 좁은 범위에서 숫자를 생성하는지 궁금해 한 적이 있습니까? 이것은 의사 난수 생성기입니다. 즉, 주기적이므로 필요하지 않은 곳에 난수를 생성한 다음 버리면 품질이 나빠집니다(반복이 더 일찍 진행됨).

4. 일부는 더 복잡한 방식으로 무작위 데이터를 얻습니다. 예를 들어, 나는 네트워크에서 뽑았고 누군가는 구매할 수도 있습니다. 그래서 내가 어렵게 얻은 데이터를 낭비해야 하는 이유는 어리석게도 버리기 때문입니다(ulong 생성, 올바른 알고리즘 작성 - 우리 방식이 아님)?

 
Alexey Navoykov :

그렇다면 왜 안 될까요? 귀하의 버전은 항상 5개의 rand()를 호출한다는 점에서 내 버전과 다릅니다. 20000 범위에서 평균 1.64번, 범위 256에서 1번. 전체적으로 rand()는 각 반복에 대해 25번 호출됩니다. , 그리고 나는 1.64*2+3 = 5.3배입니다. 일반적으로 이상한 상황은 물론, 그 이유가 정확히 무엇인지 알아낼 필요가 있습니다. 추가로 수행된 많은 비트 연산이 있기 때문에 ...

비트 단위는 가장 저렴한 작업입니다. 거의 무료입니다.

그러나 일반적으로 동의합니다. 저도 왜 그런지 모르겠습니다... 최적화의 기적일 수도 있습니다. 그래도 개선할 수 있는 것은...

 
Nikolai Semko :

비트 단위는 가장 저렴한 작업입니다. 거의 무료입니다.

그러나 일반적으로 동의합니다. 저도 왜 그런지 모르겠습니다... 최적화의 기적일 수도 있습니다. 그래도 개선할 수 있는 것은...

산술 연산 에 관한 것이 아닌 것 같습니다. 거기에 없기 때문에 모든 값은 컴파일 단계에서 계산됩니다. 그 이유는 반복 횟수를 알 수 없는 주기가 있기 때문입니다(이러한 반복 횟수는 평균 2회 미만이지만). 따라서 코드는 알려진 수의 rand() 호출에 의해 어떻게 든 최적화됩니다.
 
Vict :

1. 글쎄, 우리는 당신의 기능에서 문제가 해결되지 않고 위장 만하면 체중을 줄이지 않고 벨트를 더 단단히 조이는 것을 이해합니다.

2. Alexey 옵션에서 이것은 최악의 옵션입니다. 다른 많은 상황에서 속도는 거의 랜드() 수준이지만 시간은 일정합니다.

3. 왜 rand()가 그렇게 좁은 범위에서 숫자를 생성하는지 궁금해 한 적이 있습니까? 이것은 의사 난수 생성기입니다. 즉, 주기적이므로 필요하지 않은 곳에 난수를 생성한 다음 버리면 품질이 나빠집니다(반복이 더 일찍 진행됨).

4. 일부는 더 복잡한 방식으로 임의의 데이터를 얻습니다. 예를 들어, 나는 네트워크에서 뽑았고 누군가는 구매할 수도 있습니다. 그래서 내가 어렵게 얻은 데이터를 낭비해야 하는 이유는 어리석게도 버리기 때문입니다(ulong 생성, 올바른 알고리즘 작성 - 우리 방식이 아님)?

글쎄, 이것은 이미 지루하다.
0.1%라도 이 문제가 눈에 띄는 상황을 재현하려면 다음 값 이상의 범위에서 작동해야 합니다.

  • (ULONG_MAX)/1000= randUlong() 함수의 경우 18446744073709551
  • (UINT_MAX)/1000= randUint() 함수의 경우 4294967

그런 범위를 사용한 적이 있습니까? 그렇다면 왜 그런 검사와 루프를 넣습니까?
선의 최고의 적.

개인적으로, 실제로 제 난수 생성 범위는 2000, 최대 4000으로 제한됩니다. Rand()는 이를 위해 아주 잘 작동합니다.
이것을 내 코드에 붙여넣습니다.

 ulong t= GetMicrosecondCount ();
   for ( int i= 0 ;i<size;i++)
     {
      X[i]= ushort ( rand ()%W.Width);
      Y[i]= ushort ( rand ()%W.Width);
      clr[i]=XRGB( rand ()% 256 , rand ()% 256 , rand ()% 256 );
     }
   t= GetMicrosecondCount ()-t;
   Print ("Время формирования случайных массивов = "+ string (t)+" микросекунд. Всего сгенерировано "+ string (size* 5 )+" случайных чисел rand ()%W.Width");
   Canvas.Erase();
   for ( int i= 0 ;i<size;i++) Canvas.PixelSet(X[i],Y[i],clr[i]);
   Canvas.Update();
   Sleep ( 2000 );

그리고 rand() 함수의 "부정직"(rand()%20000 변형의 경우와 같이)을 눈치채지 못할 것이며 포인트는 시각적으로 균일한 간격을 유지하므로 매우 잘 작동하고 가장 빠릅니다.

위협 프로세서 개발자가 rand() 값을 2 ^ 15 = 32768로 제한한 것은 헛된 것이 아닙니다. 그들은 어리석은 사람들이 아닙니다. 이것은 실제 작업의 99%를 완전히 다룹니다.
그리고 "어이없는"아이디어를 좋아하는 사람들에게는 옵션으로 충분합니다.

 ulong randUlong( ulong max= ULONG_MAX ){ return ((( ulong ) rand ()<< 60 )|(( ulong ) rand ()<< 45 )|(( ulong ) rand ()<< 30 )|(( ulong ) rand ()<< 15 )|( ulong ) rand ())%max;}
파일:
 
Nikolai Semko :

개인적으로, 실제로 제 난수 생성 범위는 2000, 최대 4000으로 제한됩니다. Rand()는 이를 위해 아주 잘 작동합니다.
이것을 내 코드에 붙여넣습니다.

그리고 rand() 함수의 "부정직"(rand()%20000 변형의 경우와 같이)을 눈치채지 못할 것이며 포인트는 시각적으로 균일한 간격을 유지하므로 매우 잘 작동하고 가장 빠릅니다.

즐기세요. 상관없어요. 특히 %의 오른쪽이 RAND_MAX+1(256 또는 1024)의 배수인 경우.

위협 프로세서 개발자가 rand() 값을 2 ^ 15 = 32768로 제한한 것은 헛된 것이 아닙니다. 그들은 어리석은 사람들이 아닙니다. 이것은 실제 작업의 99%를 완전히 다룹니다.
그리고 "어이없는"아이디어를 좋아하는 사람들에게는 옵션으로 충분합니다.

프로세서 개발자는 어떻습니까? 생성기 - 소프트웨어가 구현되었습니다. 유일한 요구 사항은 RAND_MAX >= 32767이고 최소 2^32의 기간입니다. 따라서 마이크로 리터에는 "최소"에서 매우 빈약한 생성기가 있습니다.

그리고 가장 먼 시력은 스스로 정직한 랜드 ()를 만들 것입니다 (다중성이없는 경우), 이것은 참고서에서도 권장됩니다.