توليد الأرقام العشوائية الآمنة في الخيط لتكامل مونتي كارلو

StackOverflow https://stackoverflow.com/questions/3772100

سؤال

أنا أحاول كتابة شيء يحسب بسرعة كبيرة للغاية أرقام عشوائية ويمكن تطبيقه على مؤشرات ترابط متعددة. الكود الحالي الخاص بي هو:

/* Approximating PI using a Monte-Carlo method. */

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <omp.h>
#define N 1000000000  /* As lareg as possible for increased accuracy */

double random_function(void);

int main(void)
{
   int i = 0;
    double X, Y;
   double count_inside_temp = 0.0, count_inside = 0.0;
   unsigned int th_id = omp_get_thread_num();
   #pragma omp parallel private(i, X, Y) firstprivate(count_inside_temp)
   {
      srand(th_id);
      #pragma omp for schedule(static)
      for (i = 0; i <= N; i++) {
         X = 2.0 * random_function() - 1.0;
         Y = 2.0 * random_function() - 1.0;
         if ((X * X) + (Y * Y) < 1.0) {
        count_inside_temp += 1.0;
     }
  }
  #pragma omp atomic
      count_inside += count_inside_temp;
   }
   printf("Approximation to PI is = %.10lf\n", (count_inside * 4.0)/ N);
   return 0;
}

double random_function(void)
{
   return ((double) rand() / (double) RAND_MAX);
}

هذا يعمل ولكن من مراقبة مدير موارد أعرف أنه لا يستخدم جميع المواضيع. هل يعمل راند () للرمز متعدد مؤشرات الترابط؟ وإذا لم يكن هناك بديل جيد؟ شكرا جزيلا. جاك

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

المحلول

هو rand() موضوع آمن؟ ممكن و ممكن لا:

لا تحتاج وظيفة RAND () إلى إعادة الدخول. وظيفة غير مطلوبة لإعادة الدخول ليست مطلوبة لتكون آمنة مؤشرات الخيط. "

اختبار واحد وممارسة التعلم الجيد هو استبدال المكالمة إلى rand() مع ، على سبيل المثال ، عدد صحيح ثابت وشاهد ما يحدث.

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

  1. وظيفتان ، واحدة لتعيين البذرة الأولية (على سبيل المثال srand(seed)) وواحد لاسترداد القيمة التالية من التسلسل (على سبيل المثال rand()). يتم تخزين حالة PRNG داخليًا في نوع من المتغيرات العالمية. إن إنشاء رقم عشوائي جديد إما لن يكون آمنًا للخيط (يصعب تحديده ، ولكن لن يكون دفق الإخراج قابلًا للتكرار) أو سيكون بطيئًا في التعليمات البرمجية المتعددة (ينتهي بك الأمر ببعض التسلسل حول قيمة الحالة).
  2. واجهة حيث تتعرض حالة PRNG لمبرمج التطبيق. هنا عادة ما يكون لديك ثلاث وظائف: init_prng(seed), الذي يعيد بعض التمثيل الغامق لحالة PRNG ، get_prng(state), الذي يعيد رقمًا عشوائيًا ويغير متغير الحالة ، و destroy_peng(state), ، والتي تنظف فقط الذاكرة المخصصة وهلم جرا. يجب أن يكون كل من PRNGs مع هذا النوع من واجهة برمجة التطبيقات آمنة وتشغيله بالتوازي مع عدم وجود قفل (لأنك مسؤول عن إدارة متغير الحالة المحلي الآن.

أنا أكتب بشكل عام في فورتران واستخدام لاد تنفيذ Mersenne Twister PRNG (هذا الرابط يستحق القراءة). هناك الكثير من PRNG المناسبة في C والتي تعرض الدولة لسيطرتك. prng يبدو جيدًا واستخدام هذا (مع التهيئة وتدمير المكالمات داخل المنطقة المتوازية ومتغيرات الحالة الخاصة) يجب أن يمنحك تسريعًا لائقًا.

أخيرًا ، في كثير من الأحيان ، يمكن صنع PRNGs لأداء أفضل إذا طلبت سلسلة كاملة من الأرقام العشوائية في GO واحدة (على سبيل المثال ، يمكن للمترجم أن يتجهت إلى داخل PRNG Internals). بسبب هذه المكتبات غالباً ما يكون لها شيء مثل get_prng_array(state) الوظائف التي تعيدك إلى صفيف مليء بالأرقام العشوائية كما لو كنت تضع get_prng في حلقة تملأ عناصر الصفيف - يفعلون ذلك بسرعة أكبر. سيكون هذا تحسينًا ثانيًا (وسيحتاج إلى حلقة إضافية داخل التوازي للحلقة. من الواضح أنك لا تريد أن تنفد من مساحة المكدس لكل رواية القيام بذلك!

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top