تولید اعداد تصادفی

روش‌های فیزیکی

برخی از پدیده‌های طبیعی الگوهای مناسبی برای تولید این اعداد هستند به عنوان مثال برخی پدیده‌های فیزیکی از جمله اختلالات حرارتی در دیودهای زنر (Zener Diodes) دارای رفتاری کاملاً تصادفی هستند و می‌توانند پایه‌ای برای تولید RNGهای فیزیکی و سخت‌افزاری باشند.
همانطور که اشاره شد، الگوهای طبیعی جالبی برای تولید اعداد تصادفی وجود دارد؛ یک روش متداول استفاده از یک تابع درهم ساز (که ورودی اش جریانی از فریم‌های ویدئوییٍ یک منبع غیرقابل پیش‌بینی می‌باشد) است. به عنوان مثال لاواراند (Lavarand)از تصاویر تعدادی لامپ لاوا(Lava Lamps) استفاده کرد.
Lithium Technologies از تصاویر آسمان و Random.org از صداهای آشفته جوی استفاده می‌کند.

تولید اعداد تصادفی در رایانه

از آن‌جایی‌که رایانه‌ها ماشین‌هایی از نوع معیّن (Deterministic) هستند، با دریافت ورودی یکسان، همیشه یک خروجی بیرون می‌دهند. ازین رو تولید اعداد تصادفی در رایانه مبحثی است که در این مقاله به بررسی آن می‌پردازیم.
در زبان‌های برنامه‌نویسی گوناگون، تابعی وجود دارد که عددی تصادفی و معمولاً در بازهٔ صفر و یک تولید می‌کند. این تابع باید به گونه‌ای باشد که با چند بار تولید عدد تصادفی کاربر قادر به حدس زدن و پیدا کردن قاعده و الگویی در ایجاد این اعداد نشود.
هر بار که این تابع صدا زده می‌شود، رایانه عدد تولید شدهٔ پیشین را به عنوان ورودی جدید تابع تولید عدد تصادفی می‌فرستد. منشاء مشکل نیز در همین مرحله است.
هر بار که این تابع صدا زده شود، بر اساس ماهیت جبری ماشین و با توجه به مقدار اولیهٔ فرستاده شده به تابع تولید عدد تصادفی (seed) باید با یک دنباله از اعداد مشابه یکدیگر مواجه شویم.

مثال در دنیای واقعی

در زبان برنامه‌نویسی جاوا، کلاسی وجود دارد با نام Random که دو نوع Constructor دارد. نوع اول آن ورودی دریافت نمی‌کند ولی نوع دوم آن یک عدد long به عنوان seed که همان ورودی اولیهٔ تابع تولید عدد تصادفی است، دریافت می‌کند.
یک شیٔ از این کلاس برای تولید دنباله‌ای از اعداد شبهتصادفی به کار می‌رود. این کلاس از جاوا دارای متدهایی مانند next که برای دریافت عدد شبه تصادفی بعدی است، است. اگر seed یا مقدار اولیهٔ فرستاده شده به Constructor یکسان باشد. ما با گرفتن اعداد بعدی از دو شیٔ با دنباله‌ای کاملاً یکسان از اعداد مواجه می‌شویم. در زیر قسمتی از تابع next در کلاس Random را مشاهده می‌کنید.
 synchronized protected int next(int bits) {
       seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L <<48) - 1);
       return (int)(seed>>> (48 - bits));
 }
این تابع و در واقع روش پیش‌روی و به دست آوردن seed یا مقدار اولیهٔ بعدی در جاوا، برگرفته از روش پیشنهادی دونالد کنوت در کتاب هنر برنامه‌نویسی رایانه می‌باشد.

چگونه مقدار اولیه مناسب را پیدا کنیم؟

در برنامه‌نویسی به عنوان مثال برای نوشتن یک بازی راه‌حل‌های گوناگونی مانند قرار دادن مقدار اولیه برابر با تعداد بازی‌های انجام شده بر روی رایانه یا ذخیرهٔ خروجی آخرین seed از برنامهٔ قبلی در حال اجرا است. با اینحال کماکان مشکل مقدار دهی اولین seed پابرجاست.

اولین مقدار اولیه

راحت‌ترین راه حل این مسئله در دنیای کامپیوتر استفاده از زمان فعلی دستگاه است. کامپیوترهای امروزی زمان را با دقت میلی‌ثانیه در دسترس دارند. برنامه‌ها می‌توانند زمان اولین اجرای خود را به عنوان seed به اولین باری که تابع تولید اعداد تصادفی صدا زده می‌شود، بفرستند. ولی اگر باز هم دونفر به‌طور کاملاً هم‌زمان برنامه را اجرا کنند خروجی یکسان دریافت خواهند کرد. این مشکل هم با افزودن معیارهای دیگری به seed مانند زمان آخرین کلیک ماوس (Mouse Click)، مدت زمان بالا بودن سیستم‌عامل و مواردی مشابه، به مقدار زیادی کاهش داد. با افزودن این معیارها و معیارهای مشابه دیگر به برنامه احتمال ایجاد تشابه را به سمت صفر کاهش می‌دهیم.
در همان زبان برنامه‌نویسی جاوا که به عنوان نمونه آورده شد، ورودی Constructor یک عدد از نوع اولیهٔ long به عنوان ورودی می‌گیرد. این عدد long یک عدد ۶۴ بیتی در جاوا است که خود باعث محدود شدن seed و امکان به وجود آمدن اعداد تصادفی برابر را فراهم می‌سازد.
بنابر این مشکل کاملاً حل نشده‌است.

اعداد شبه تصادفی

همانطور که دیدیم اعداد تصادفی تولید شده توسط رایانه و محاسبات ریاضی اعداد کاملاً تصادفی نبوده و از اینرو این اعداد را اعداد شبه تصادفی می‌نامند.