تاریخچه تحول مکانیزمهای تولید اعداد تصادفی تا داتنت ۱۱
نویسنده: وحید نصیری
تاریخ: ۱۴۰۵/۰۴/۰۹ ۰۹:۱۵
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
System.Random که از اولین نسخههای داتنت وجود داشته، به مرور زمان دستخوش تغییرات ساختاری بزرگی شده تا مشکلاتی مانند عدم امنیت در محیطهای چندنخی (Thread Safety)، سوءاستفادههای امنیتی و محدودیتهای نوع داده (Data Type) را برطرف کند. در ادامه تاریخچه تکاملی مکانیزمهای تولید اعداد تصادفی در نگارشهای مختلف داتنت را بررسی میکنیم:System.Random بود. این کلاس با الگوریتم شبهتصادفی (PRNG) مبتنی بر الگوریتم تفاضلی دونالد کنوت (Donald Knuth) کار میکرد.Next را روی یک نمونه مشترک از Random صدا میزدند، وضعیت داخلی کلاس خراب میشد و در بسیاری از مواقع، پس از آن به طور مداوم عدد 0 را برمیگرداند.Random در یک زمان بسیار کوتاه (مثلاً درون یک حلقه) ساخته میشدند، به دلیل Seed یکسان (زمان سیستم)، همگی اعداد کاملاً مشابهی تولید میکردند.Next() (برای int)، NextDouble() و NextBytes() محدود میشدند. برای تولید انواع دیگر مانند byte یا long باید فرمولهای ریاضی دستی نوشته میشد.RNGCryptoServiceProvider استفاده کنند که کندتر بود اما امنیت بالایی داشت.Random، هرکدام Seed متفاوتی دریافت کنند و اعداد متفاوتی تولید کنند. با این حال، مشکل Thread-Safety همچنان پابرجا بود.System.Random از الگوریتم قدیمی Knuth به الگوریتم مدرنتر و سریعتر xoshiro256 (یا xoroshiro128 برای سیستمهای ۳۲ بیتی) تغییر یافت. این تغییر باعث شد عملکرد (Performance) تولید اعداد تصادفی به شدت بهبود یابد و کیفیت توزیع آماری اعداد تصادفی نیز بهتر شود.Random.SharedRandom.Shared بود.Random را در اختیار شما میگذارد. دیگر نیازی به ساختن نمونههای جدید با کلمه کلیدی new نبود و نیازی هم به قفلگذاری (Locking) در محیطهای چندنخی وجود نداشت.GetItems و Shuffle در نسخههای بعدی بر پایه این ساختار شکل گرفتند.Random را گسترش داد:NextSingle() (برای نوع float) در داتنت ۵ معرفی شده بودند، اما در داتنت ۷ الگوهای کاربردیتری برای تولید توابع توزیع آماری اضافه شد.Shuffle برای برهم زدن تصادفی آرایهها/لیستها و متد GetItems برای انتخاب تصادفی چند آیتم از یک مجموعه معرفی شدند که کارهای رایج توسعهدهندگان را بسیار آسان کرد.int (مانند long یا byte)، توسعهدهندگان هنوز باید دست به دامن ترفندهایی مانند متد NextBytes یا تبدیل نوعهای دستی (مانند همان مثالی که در متن خود آوردید) میشدند.NextIntegerSystem.Random را برطرف کرده است.Next() فقط خروجی int (علامتدار ۳۲ بیتی) میداد. برای گرفتن یک byte یا short تصادفی، باید سقف محدوده را جابجا میکردید و نوع خروجی را به صورت صریح (Explicit Cast) تغییر میدادید. این کار کدهای ناخوانا تولید میکرد و احتمال خطای خارج از محدوده (Overflow) وجود داشت.NextInteger، اکنون تمام انواع داده صحیح (Integral Types) از جمله byte, sbyte, short, ushort, int, uint, long, ulong, nint, nuint به صورت بومی و بدون نیاز به کست کردن پشتیبانی میشوند. همچنین این متدها اورلودهایی برای تعیین محدوده (Range) دارند که امنیت کد را به شدت بالا میبرد:var randomByte = Random.Shared.NextInteger<byte>(); Console.WriteLine(randomByte);
int.xoshiro برای سرعت بیشتر.Random.Shared.Shuffle و GetItems.NextInteger برای پوشش تمام انواع دادههای صحیح.