[c++] الطريقة الموصى بها لتهيئة srand؟


6 Answers

هذا ما استخدمته لبرامج سطر الأوامر الصغيرة التي يمكن تشغيلها بشكل متكرر (عدة مرات في الثانية):

unsigned long seed = mix(clock(), time(NULL), getpid());

أين المزيج هو:

// http://www.concentric.net/~Ttwang/tech/inthash.htm
unsigned long mix(unsigned long a, unsigned long b, unsigned long c)
{
    a=a-b;  a=a-c;  a=a^(c >> 13);
    b=b-c;  b=b-a;  b=b^(a << 8);
    c=c-a;  c=c-b;  c=c^(b >> 13);
    a=a-b;  a=a-c;  a=a^(c >> 12);
    b=b-c;  b=b-a;  b=b^(a << 16);
    c=c-a;  c=c-b;  c=c^(b >> 5);
    a=a-b;  a=a-c;  a=a^(c >> 3);
    b=b-c;  b=b-a;  b=b^(a << 10);
    c=c-a;  c=c-b;  c=c^(b >> 15);
    return c;
}
Question

أحتاج إلى طريقة "جيدة" لتهيئة مولد الأرقام الزائفة العشوائية في C ++. لقد وجدت مقالة تنص على ما يلي:

من أجل توليد أرقام شبيهة بطريقة عشوائية ، عادة ما تتم تهيئة srand إلى بعض القيمة المميزة ، مثل تلك المرتبطة بوقت التنفيذ. على سبيل المثال ، تختلف القيمة التي يتم إرجاعها بواسطة الدالة time (تم التصريح عنها في ctime header) كل ثانية ، وهي مميزة بشكل كافٍ لمعظم احتياجات randoming.

ليس Unixtime مميزًا بما فيه الكفاية لطلبي. ما هي أفضل طريقة لتهيئة هذا؟ نقاط المكافأة إذا كانت محمولة ، ولكن سيتم تشغيل الكود بشكل أساسي على مضيفات Linux.

كنت أفكر في القيام ببعض pid / unixtime الرياضيات للحصول على كثافة العمليات ، أو ربما قراءة البيانات من /dev/urandom .

شكر!

تصحيح

نعم ، أنا بالفعل أبدأ طلبي عدة مرات في الثانية وواجهت تصادمات.







لأولئك الذين يستخدمون Visual Studio هنا طريقة أخرى:

#include "stdafx.h"
#include <time.h>
#include <windows.h> 

const __int64 DELTA_EPOCH_IN_MICROSECS= 11644473600000000;

struct timezone2 
{
  __int32  tz_minuteswest; /* minutes W of Greenwich */
  bool  tz_dsttime;     /* type of dst correction */
};

struct timeval2 {
__int32    tv_sec;         /* seconds */
__int32    tv_usec;        /* microseconds */
};

int gettimeofday(struct timeval2 *tv/*in*/, struct timezone2 *tz/*in*/)
{
  FILETIME ft;
  __int64 tmpres = 0;
  TIME_ZONE_INFORMATION tz_winapi;
  int rez = 0;

  ZeroMemory(&ft, sizeof(ft));
  ZeroMemory(&tz_winapi, sizeof(tz_winapi));

  GetSystemTimeAsFileTime(&ft);

  tmpres = ft.dwHighDateTime;
  tmpres <<= 32;
  tmpres |= ft.dwLowDateTime;

  /*converting file time to unix epoch*/
  tmpres /= 10;  /*convert into microseconds*/
  tmpres -= DELTA_EPOCH_IN_MICROSECS; 
  tv->tv_sec = (__int32)(tmpres * 0.000001);
  tv->tv_usec = (tmpres % 1000000);


  //_tzset(),don't work properly, so we use GetTimeZoneInformation
  rez = GetTimeZoneInformation(&tz_winapi);
  tz->tz_dsttime = (rez == 2) ? true : false;
  tz->tz_minuteswest = tz_winapi.Bias + ((rez == 2) ? tz_winapi.DaylightBias : 0);

  return 0;
}


int main(int argc, char** argv) {

  struct timeval2 tv;
  struct timezone2 tz;

  ZeroMemory(&tv, sizeof(tv));
  ZeroMemory(&tz, sizeof(tz));

  gettimeofday(&tv, &tz);

  unsigned long seed = tv.tv_sec ^ (tv.tv_usec << 12);

  srand(seed);

}

ربما تكون مبالغة في بعض الشيء ولكنها تعمل جيدًا للفترات الزمنية السريعة. وظيفة gettimeofday وجدت here .

تحرير: على مزيد من التحقيق قد يكون rand_s بديلا جيدا ل Visual Studio ، انها ليست مجرد راند آمن () ، انها مختلفة تماما ولا تستخدم البذور من srand. لقد افترضت أنها مطابقة تقريباً للراند "أكثر أماناً".

لاستخدام rand_s فقط لا تنس # تعريف _CRT_RAND_S قبل تضمين stdlib.h.




#include <stdio.h>
#include <sys/time.h>
main()
{
     struct timeval tv;
     gettimeofday(&tv,NULL);
     printf("%d\n",  tv.tv_usec);
     return 0;
}

tv.tv_usec في microseconds. هذا يجب أن يكون بذور مقبولة.




ضمّن رأس الصفحة في الجزء العلوي من البرنامج ، واكتب:

srand(time(NULL));

في البرنامج قبل أن تعلن رقمك العشوائي. في ما يلي مثال على برنامج يقوم بطباعة رقم عشوائي بين واحد وعشرة:

#include <iostream>
#include <iomanip>

using namespace std;

int main()
{
   //Initialize srand
   srand(time(NULL));

   //Create random number
   int n = rand() % 10 + 1;

   //Print the number
   cout << n << endl; //End the line

   //The main function is an int, so it must return a value
   return 0;
}



أقترح أن ترى ملف unix_random.c في كود mozilla. (أعتقد أنه mozilla / security / freebl / ...) يجب أن يكون في مكتبة freebl.

هناك يستخدم معلومات مكالمة النظام (مثل pwd ، netstat ....) لتوليد الضجيج لعدد عشوائي ، هو مكتوب لدعم معظم المنصات (التي يمكن أن تكسب لي نقطة المكافأة: D).




C ++ 11 random_device

إذا كنت بحاجة إلى جودة معقولة فلا ينبغي عليك استخدام الراند () في المقام الأول ؛ يجب عليك استخدام المكتبة <random> . إنه يوفر الكثير من الوظائف الرائعة مثل مجموعة متنوعة من المحركات لمقايضات الجودة / الحجم / الأداء المختلفة ، وإعادة الدخول ، والتوزيعات المحددة مسبقًا حتى لا ينتهي بك الأمر إلى جعلها خاطئة. بل قد يوفر وصولاً سهلاً إلى البيانات العشوائية غير الحتمية ، (على سبيل المثال ، / dev / random) ، وفقًا للتنفيذ الخاص بك.

#include <random>
#include <iostream>

int main() {
    std::random_device r;
    std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
    std::mt19937 eng(seed);

    std::uniform_int_distribution<> dist{1,100};

    for (int i=0; i<50; ++i)
        std::cout << dist(eng) << '\n';
}

eng هو مصدر العشوائية ، وهنا تنفيذ مدمج اعصار مرسين. نحن نزرعها باستخدام random_device ، والتي في أي تطبيق لائق ستكون RNG غير محدد ، و seed_seq لدمج أكثر من 32 بت من البيانات العشوائية. على سبيل المثال في libc ++ random_device accesses / dev / urandom بشكل افتراضي (على الرغم من أنه يمكنك إعطاؤه ملفًا آخر للدخول إليه بدلاً منه).

بعد ذلك ننشئ توزيعة بحيث ، في ضوء مصدر عشوائي ، ستؤدي المكالمات المتكررة إلى التوزيع إلى توزيع منتظم للقمات من 1 إلى 100. ثم ننتقل إلى استخدام التوزيع بشكل متكرر وطباعة النتائج.




Related