في هذه المقالة ، سترى خوارزميات الدراجات الأكثر تنوعًا لإنشاء أرقام عشوائية.حول أي مقال
حول الخوارزميات إنشاء أرقام عشوائية زائفة تختلف في جودة النتيجة وسرعة التنفيذ. ستكون المقالة مفيدة لأولئك الذين يرغبون في الحصول على عدد عالي الأداء من الجيل في برامجهم أو مطوري البرامج للتحكم الدقيق والمنصات القديمة مثل ZX Spectrum أو MSX.C ++ راند
أول شيء يتعلمه مبرمج C ++ المبتدئ حول الحصول على منزل عشوائي هو وظيفة الراند ، التي تولد رقمًا عشوائيًا بين 0 و RAND_MAX. يتم وصف ثابت RAND_MAX في ملف stdlib.h وهو 32'767 ، ولكن قد لا يكون هذا هو الحال ، على سبيل المثال ، في Linux ( انظر التعليق ). إذا كان rand () في المترجم الخاص بك يولد أرقامًا ضمن 32'767 (0x7FFF) وتريد الحصول على عدد عشوائي من الحجم الكبير ، فيمكن اعتبار الرمز أدناه كحل لهذه المشكلة:int64_t A = rand();
A <<= 15;
A |= rand();
A <<= 15;
A |= rand();
A <<= 15;
A |= rand();
A <<= 3;
A |= rand() & 0b111;
كان تنفيذ وظيفة الراند في لغة C القديمة بسيطًا وشبهه:static unsigned long int next = 1;
int rand()
{
next = next * 1103515245 + 12345;
return (unsigned int)(next / 65536) % 32768;
}
لم يكن لهذا التطبيق توزيع جيد جدًا للأرقام وقد تم تحسينه الآن في C ++. أيضًا ، توفر مكتبة C ++ القياسية طرقًا إضافية للحصول على رقم عشوائي ، والتي سيتم مناقشتها أدناه.C ++ 11 STL عشوائي
ظهر هذا التنوع العشوائي في C ++ 11 ويتكون من مجموعة الفئات التالية: minstd_rand و mt19937 و ranlux و knuth_b وتنويعاتها المختلفة.لمنع تسلسل الأرقام العشوائية من التكرار في كل مرة يتم فيها تشغيل البرنامج ، يتم تحديد "حبة" المولد العشوائي الزائف في شكل الوقت الحالي أو ، في حالة بعض الألعاب القديمة (وليس فقط) ، الفترات الفاصلة بين ضغطات المفاتيح من لوحة المفاتيح / عصا التحكم. تقترح المكتبة العشوائية استخدام std :: random_device للحصول على الحبوب بشكل أفضل من الوقت (NULL) ، ومع ذلك ، في حالة مترجم MinGW على Windows ، لا تعمل الوظيفة عمليًا كما ينبغي. ما يزال…
#include <random>
#include <ctime>
std::mt19937 engine;
engine.seed(std::time(nullptr));
int val = engine();
قد تعمل بعض الخوارزميات في STL عشوائيًا بشكل أسرع من rand () ، ولكنها تعطي تسلسلًا أقل جودة للأرقام العشوائية.PRNG - مولد الأرقام العشوائية الزائفة
يمكنك اعتبار هذا الاسم مرادفًا لطريقة التطابق الخطي. خوارزميات PRNG تشبه تطبيق الراند في C وتختلف فقط في الثوابت.unsigned PRNG()
{
static unsigned seed = 1;
seed = (seed * 73129 + 95121) % 100000;
return seed;
}
خوارزميات PRNG سريعة وسهلة التنفيذ في العديد من اللغات ، ولكن ليس لديها فترة كبيرة.Xorshift
تحتوي الخوارزمية على العديد من الاختلافات ، تختلف عن بعضها البعض حسب الفترة والسجلات المستخدمة. يمكن الاطلاع على تفاصيل وأنواع XorShift على ويكيبيديا أو حبري. سأعطي أحد الخيارات بتسلسل 2 في الدرجة 128.struct seed_t
{
unsigned x = 1;
unsigned y = 123;
unsigned z = 456;
unsigned w = 768;
};
unsigned XorShift128()
{
static seed_t s;
unsigned t = s.x^(s.x<<11);
s.x = s.y;
s.y = s.z;
s.z = s.w;
s.w = (s.w^(s.w>>19)) ^ (t^(t>>8));
return s.w;
}
هذا المولد جيد جدًا لأنه لا يحتوي على عمليات تقسيم وضرب على الإطلاق - يمكن أن يكون هذا مفيدًا في المعالجات ووحدات التحكم الدقيقة التي لا توجد بها تعليمات قسم / الضرب المجمعة (PIC16 ، Z80 ، 6502).8 بت عشوائي في محاكي z26
Z26 هو محاكي لبادئة Atari2600 قديمة ، في الكود يمكنك العثور على رمز عشوائي موجّه للعمل مع سجلات 1 بايت.
void P2_Read_Random()
{
P2_sreg =
(((((P2_sreg & 0x80) >> 7) ^
((P2_sreg & 0x20) >> 5)) ^
(((P2_sreg & 0x10) >> 4) ^
((P2_sreg & 0x08) >> 3))) ^ 1) |
(P2_sreg << 1);
DataBus = P2_sreg;
}
بمجرد أن اضطررت إلى تنفيذ هذه الخوارزمية لـ z80:رمز التجميع; z26
; a - output
; rdseed - 1
randz26:
exx
ld a,(rdseed)
and 20h
sra a
sra a
sra a
sra a
sra a
ld h, a
ld a,(rdseed)
and 80h
sra a
sra a
sra a
sra a
sra a
sra a
sra a
xor h
ld l, h
ld a,(rdseed)
and 08h
sra a
sra a
sra a
ld h, a
ld a,(rdseed)
and 10h
sra a
sra a
sra a
sra a
xor h
ld h, a
ld a, l
xor h
xor 1
ld h, a
ld a,(rdseed)
sla a
or h
ld (rdseed),a
exx
ret
المدمجة العشوائية ل Z80 من جو Wingbermuehle
إذا كنت مهتمًا بكتابة برامج للسيارات مع zilog ، فأقدم انتباهكم إلى خوارزمية من Joe Wingbermuehle (تعمل فقط على zilog):; By Joe Wingbermuehle
; a res 1 byte - out val
; rdseed res 1 byte - need for rand. != 0
rand8:
exx
ld hl,(rdseed)
ld a,r
ld d,a
ld e,(hl)
add hl,de
add a,l
xor h
ld (rdseed),hl
exx
ret
مولدات عشوائية في DOOM
في الكود المصدري للعبة Doom ، يوجد ملف مثير للاهتمام يسمى m_random.c (انظر الكود) ، والذي يصف وظيفة عشوائية "الطاولة" ، أي أنه لا توجد صيغ وسحر مع تحولات بت على الإطلاق.سأعطيك رمزًا أكثر إحكاما يوضح بوضوح تشغيل هذه الوظيفة.const uint8_t random_map[] =
{
4, 1, 63, 3,
64, 22, 54, 2,
0, 52, 75, 34,
89, 100, 23, 84
};
uint8_t get_random()
{
static uint8_t index = 0;
index = (index + 1) & 0xF;
return random_map[index];
}
فاريك ل z80; ( DOOM)
; rand_table - .
; 256 .
; a - output num
randtab:
exx
; index
ld a, (rdseed)
inc a
;and filter ; for crop array index
ld (rdseed), a
; calc array address
ld hl, rand_table
ld d, 0
ld e, a
add hl, de
ld a, (hl) ; get num from arr
exx
ret
بالطبع ، هذا ليس عشوائيًا ومن السهل التنبؤ بتسلسل الأرقام العشوائية حتى على مستوى الحدس أثناء اللعبة ، ولكن كل ذلك يعمل بسرعة كبيرة. إذا لم تكن قوة التشفير مهمة بالنسبة لك وتريد شيئًا يولد بسرعة "نوع عشوائي" ، فإن هذه الوظيفة مناسبة لك. بالمناسبة ، في Quake3 ، تبدو عشوائية بسيطة - rand () & 0x7FFF.RDRAND
بعض المعالجات الحديثة قادرة على توليد أرقام عشوائية بإرشاد مجمع واحد - RDRAND. لاستخدام هذه الوظيفة في C ++ ، يمكنك كتابة التعليمات اللازمة يدويًا باستخدام إدخالات التجميع ، أو توصيل ملف immintrin.h في GCC وتحديد أي من اختلافات دالة _rdrandXX_step ، حيث تعني XX عدد البتات في التسجيل ويمكن أن تكون 16 أو 32 أو 64.#include <immintrin.h>
unsigned val;
_rdrand32_step(&val);
إذا رأيت خطأ تجميع ، فهذا يعني أنك لم تقم بتمكين علامة -mrdrnd أو أن المترجم / المعالج الخاص بك لا يدعم هذه الأداة. قد يكون أسرع مولد للأرقام العشوائية ، ولكن هناك أسئلة حول قوة التشفير ، لذا فكر في الأمر.تنتهي
تعمل فئة std :: minstd_rand من مكتبة STL العشوائية بشكل أسرع من الراند العادي () ويمكن أن تصبح بديلاً بديلًا إذا لم تكن مهتمًا بشكل خاص بطول الفترة في minstd. قد تكون هناك اختلافات في كيفية عمل هذه الوظائف على Windows و Unix.INFA على الموضوع
PS مقالتي الأولى. اكتب ما هو غير ضروري وما يجب إضافته / تقليله