سؤال

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

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

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

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

وذلك بفضل!

تحرير

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

هل كانت مفيدة؟

المحلول

أفضل إجابة هو استخدام دفعة رقم عشوائي الأشياء.أو إذا كان لديك الوصول إلى C++11 استخدام <random> رأس.

ولكن إذا كنا نتحدث عن rand() و srand()
أفضل طريقة هي استخدام time():

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

    ...
}

تأكد من أن تفعل هذا في بداية البرنامج و ليس في كل مرة تتصل rand()!

في كل مرة كنت بدء, time() سيعود قيمة فريدة من نوعها (إلا إذا كنت بدء التطبيق عدة مرات في الثانية الواحدة).في أنظمة 32 بت, وسوف أكرر فقط كل 60 سنة أو نحو ذلك.

أنا أعلم أنك لا تعتقد الوقت هي فريدة من نوعها بما فيه الكفاية ولكن أجد أنه من الصعب الاعتقاد.لكن قد عرفت أن أكون مخطئا.

إذا كنت بدأت الكثير من النسخ من تطبيق في وقت واحد يمكنك استخدام الموقت مع الدقيقة القرار.ولكن ثم كنت عرضة لخطر من أقصر فترة زمنية قبل أن قيمة يكرر.

حسنا, لذلك إذا كنت تعتقد حقا أنك بدأت تطبيقات متعددة الثانية.
ثم استخدام الحبوب الدقيقة على جهاز ضبط الوقت.

 int main()
 {
     struct timeval time; 
     gettimeofday(&time,NULL);

     // microsecond has 1 000 000
     // Assuming you did not need quite that accuracy
     // Also do not assume the system clock has that accuracy.
     srand((time.tv_sec * 1000) + (time.tv_usec / 1000));

     // The trouble here is that the seed will repeat every
     // 24 days or so.

     // If you use 100 (rather than 1000) the seed repeats every 248 days.

     // Do not make the MISTAKE of using just the tv_usec
     // This will mean your seed repeats every second.
 }

نصائح أخرى

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

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;
}

إذا كنت في حاجة إلى أفضل مولد رقم عشوائي ، لا تستخدم libc راند.بدلا من مجرد استخدام شيء من هذا القبيل /dev/random أو /dev/urandom مباشرة (قراءة في int مباشرة منه أو شيء من هذا القبيل).

فقط فائدة حقيقية من libc راند هو أن تعطى البذور ، فإنه يمكن التنبؤ بها مما يساعد على التصحيح.

على ويندوز:

srand(GetTickCount());

يوفر أفضل البذور من time() منذ بالمللي ثانية.

C++11 random_device

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

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

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

أفضل طريقة هي استخدام آخر المزيف عدد المولدات.ميرسين الاعصار (و Wichmann-هيل) هو توصيتي.

http://en.wikipedia.org/wiki/Mersenne_twister

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

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

السؤال الحقيقي يجب أن تسأل نفسك ما العشوائية الجودة التي تحتاج إليها.

libc عشوائي هو LCG

نوعية العشوائية سوف تكون منخفضة أي مدخلات تقدمها srand مع.

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

على سبيل المثال :

struct timeb tp;
ftime(&tp);   
srand(static_cast<unsigned int>(getpid()) ^ 
static_cast<unsigned int>(pthread_self()) ^ 
static_cast<unsigned int >(tp.millitm));

أفضل عشوائية الجودة, استخدام /dev/urandom.يمكنك جعل رمز أعلاه المحمولة في استخدام دفعة::موضوع زيادة::date_time.

على c++11 إصدار أعلى صوت آخر من قبل جوناثان رايت:

#include <ctime>
#include <random>
#include <thread>

...

const auto time_seed = static_cast<size_t>(std::time(0));
const auto clock_seed = static_cast<size_t>(std::clock());
const size_t pid_seed =
      std::hash<std::thread::id>()(std::this_thread::get_id());

std::seed_seq seed_value { time_seed, clock_seed, pid_seed };

...
// E.g seeding an engine with the above seed.
std::mt19937 gen;
gen.seed(seed_value);
#include <stdio.h>
#include <sys/time.h>
main()
{
     struct timeval tv;
     gettimeofday(&tv,NULL);
     printf("%d\n",  tv.tv_usec);
     return 0;
}

التلفزيون.tv_usec في ميكروثانية.هذا ينبغي أن يكون مقبولا البذور.

افترض أن لديك وظيفة مع توقيع مثل:

int foo(char *p);

مصدر ممتاز من الكون بالنسبة عشوائي هو تجزئة التالية:

  • كامل نتيجة clock_gettime (ثواني و نانو ثانية) دون رمي انخفاض بت - هم الأكثر قيمة.
  • قيمة p, يلقي إلى uintptr_t.
  • عنوان p, يلقي إلى uintptr_t.

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

وأود أيضا تجنب استخدام rand/srand تماما, سواء من أجل عدم لمس الدولة العالمية ، بحيث يمكن أن يكون لديك المزيد من السيطرة على اللوائح التي تستخدم.ولكن الإجراء أعلاه هو جيد (إلى حد ما المحمولة) طريقة للحصول على بعض لائق الكون من دون الكثير من العمل ، بغض النظر عن اللوائح التي تستخدمها.

بالنسبة لأولئك باستخدام 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 وظيفة وجدت هنا.

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

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

طالما البرنامج يعمل فقط على لينكس (البرنامج هو قزم القابل للتنفيذ) ، ويضمن لك أن تقدم النواة العملية الخاصة بك فريدة من نوعها عشوائي في قزم aux ناقلات.نواة يعطيك 16 بايت عشوائي ، مختلفة عن كل عملية التي يمكنك الحصول عليها مع getauxval(AT_RANDOM).لاستخدام هذه srand, استخدم فقط int منهم على هذا النحو:

#include <sys/auxv.h>

void initrand(void)
{
    unsigned int *seed;

    seed = (unsigned int *)getauxval(AT_RANDOM);
    srand(*seed);
}

قد يكون من الممكن أن هذا يترجم أيضا إلى قزم أخرى النظم القائمة.لست متأكدا ما aux القيم تنفذ على أنظمة أخرى من لينكس.

تشمل الرأس في الجزء العلوي من البرنامج و كتابة:

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;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top