مولد الأرقام العشوائية

أنشئ رقمًا عشوائيًا واحدًا أو عدة أرقام ضمن أي نطاق، مع تكرار أو بدونه — باستخدام عشوائية تشفيرية.

1,448 مشاهدة

كيف تُولَّد الأرقام فعليًا؟

ليست كل أنواع "العشوائية" متساوية. Math.random()، المتوفرة في كل متصفح، مولّد شبه عشوائي سريع — حتمي في جوهره، ومن حيث المبدأ يمكن التنبؤ به إذا عرف أحدهم حالته الداخلية، ما يجعله غير مناسب لأي شيء حساس أمنيًا كالسحوبات ذات المخاطر الحقيقية. تستخدم هذه الأداة بدلًا من ذلك crypto.getRandomValues()، المولّد العشوائي الآمن تشفيريًا المدمج في المتصفح، والذي يستمد قيمه من مصادر إنتروبيا نظام التشغيل ولا يمكن التنبؤ به حتى من حيث المبدأ.

لكن امتلاك مصدر عشوائي آمن يحل نصف المشكلة فقط. فتحويل قيمة عشوائية إلى نطاق محدد (مثلًا 1-100) بطريقة ساذجة — عبر أخذ random % 100 — يُدخل انحيازًا دقيقًا لكنه حقيقي يُعرف بـانحياز باقي القسمة (modulo bias): لأن نطاق المخرجات الخام للمولّد لا يكون عادةً مضاعفًا دقيقًا للعدد 100، ينتهي الأمر ببعض البواقي لتصبح أكثر احتمالًا قليلًا من غيرها. الانحياز صغير، لكنه حقيقي ويتراكم عبر سحوبات كثيرة — وهو تمامًا النوع من الأشياء التي لا ينبغي أن توجد في قرعة يُفترض أنها عادلة.

الحل هو أخذ العينات بالرفض (rejection sampling): بدلًا من إجبار كل قيمة خام على الدخول في النطاق عبر باقي القسمة، تُستبعد القيم الخام الواقعة خارج النطاق ويُسحب رقم جديد إلى أن يقع بشكل نظيف ضمن مضاعف دقيق للنطاق المستهدف. يضمن هذا توزيعًا موحدًا حقًا — كل رقم في النطاق له احتمال متساوٍ تمامًا — مقابل الحاجة أحيانًا إلى سحب إضافي أو اثنين، وهو أمر غير محسوس عند السرعات المعنية.

اختر حدًا أدنى وحدًا أقصى وعدد الأرقام المطلوبة؛ فعّل خيار بلا تكرار لمنع تكرار الأرقام، وهو ما تحتاجه القرعات وسحوبات الجوائز وأخذ العينات والألعاب حين لا ينبغي للمشاركة نفسها أن تفوز مرتين. كل شيء يعمل على الجهاز المحلي — لا يُرسل أي رقم أو يُخزَّن في أي مكان، وتحديث الصفحة ينتج سحبًا جديدًا تمامًا.

أمور تستحق المعرفة

  • انحياز باقي القسمة غير مرئي في حفنة من السحوبات لكنه يصبح قابلًا للاكتشاف إحصائيًا عبر الآلاف منها — يزيل أخذ العينات بالرفض هذا الانحياز تمامًا بدلًا من مجرد تقليصه.
  • كون crypto.getRandomValues() "آمنًا تشفيريًا" يعني أن مخرجاته لا يمكن التنبؤ بها حتى من قِبل شخص رأى المخرجات السابقة — خاصية لا تملكها Math.random() صراحة ولم تُصمَّم أبدًا لامتلاكها.
  • النطاق شامل من الطرفين: يمكن أن ينتج سحب 1-10 كلًا من 1 و10، وليس فقط القيم الواقعة بينهما تمامًا.
  • لقرعة قابلة للتدقيق، رقّم المشاركين من 1 إلى N، اضبط النطاق تبعًا لذلك، فعّل خيار بلا تكرار، والتقط لقطة شاشة للنتيجة، لأنه لا يُخزَّن شيء من جهة الخادم بعد السحب.

الأسئلة الشائعة

هل الأرقام عشوائية حقًا، أم "عشوائية بما يكفي" فقط؟

تأتي من crypto.getRandomValues()، الذي يستمد قيمه من مصدر الإنتروبيا التشفيري لنظام التشغيل - غير قابلة للتنبؤ من حيث المبدأ لا من الناحية العملية فقط، بخلاف Math.random() البسيطة التي تستخدمها معظم النصوص العشوائية العادية.

ما هو انحياز باقي القسمة، وهل تعاني منه هذه الأداة؟

تحويل قيمة عشوائية إلى نطاق بطريقة ساذجة عبر random % N يفضّل بعض الأرقام قليلًا على غيرها، لأن النطاق الخام للمولّد عادةً ليس مضاعفًا دقيقًا لـ N. تتجنب هذه الأداة ذلك عبر أخذ العينات بالرفض: تُستبعد القيم الخام الواقعة خارج النطاق ويُعاد سحبها إلى أن تُضمَن نتيجة موحدة.

ما هو أخذ العينات بالرفض، ببساطة؟

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

هل يمكنني استخدام هذا في قرعة جوائز؟

نعم. رقّم المشاركين من 1 إلى N، اضبط النطاق تبعًا لذلك، فعّل خيار بلا تكرار، وأنشئ عدد الفائزين الذي تحتاجه. التقط لقطة شاشة للسجلات، لأن النتائج لا تُخزَّن في أي مكان بعد السحب.

هل يشمل النطاق كلًا من الحد الأدنى والحد الأقصى؟

نعم - النطاق شامل من الطرفين. يمكن أن ينتج سحب 1-10 كلًا من 1 و10، تمامًا كما لو سُحبت أوراق مرقّمة من قبعة.

التعليقات

لا توجد تعليقات بعد — كن أول من يكتب تعليقًا!

أدوات مشابهة