[C++] الطريقة الموصى بها لتهيئة سراند؟


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 ++. لقد وجدت مقالة تنص على ما يلي:

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

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

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

شكر!

تصحيح

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







#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 في ميكروثانية. وينبغي أن تكون هذه البذور مقبولة.




أقترح عليك رؤية الملف unix_random.c في رمز موزيلا. (تخمين هو موزيلا / الأمن / فريبل / ...) يجب أن يكون في مكتبة فريلبل.

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




C ++ 11 random_device

إذا كنت بحاجة إلى نوعية معقولة ثم يجب أن لا تستخدم راند () في المقام الأول؛ يجب عليك استخدام المكتبة <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، والتي في أي تنفيذ لائق سيكون رنغ غير ديترميناليستيك، و seed_seq الجمع بين أكثر من 32 بت من البيانات العشوائية. على سبيل المثال في ليبك ++ random_device أسيس / ديف / أوراندوم بشكل افتراضي (على الرغم من أنك يمكن أن تعطيه ملف آخر للوصول بدلا من ذلك).

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




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

#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);

}

ربما قليلا مبالغة ولكن يعمل بشكل جيد لفترات سريعة. وظيفة جيتتموفداي وجدت هنا .

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

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