tinyrand مواصفات RNG خفيفة الوزن والعديد من التطبيقات الفائقة في الصدأ. tinyrand هو no_std ولا يستخدم مخصص كومة.
tinyrand ؟std ، وهذا يعني أنه قابل للتضمين-فهو يعمل على متحكم وبيئات معاداة (بدون نظام تشغيل).Mock للاختبار رمز يعتمد على الأرقام العشوائية. هذا هو ، إذا كنت تهتم بتغطية الكود.فيما يلي مقارنة بين العديد من prngs البارزة.
| prng | خوارزمية | النطاق الترددي (GB/S) | |
|---|---|---|---|
rand | Chacha12 | 2.4 | |
tinyrand | SplitMix | 6.5 | |
tinyrand | XorShift | 6.7 | |
fastrand | ويراند | 7.5 | |
tinyrand | ويراند | 14.6 |
TL ؛ DR: tinyrand هو 2x أسرع من fastrand و 6x أسرع من rand .
من المستحيل معرفة ما إذا كان PRNG معينًا جيدًا ؛ الجواب الاحتمالي. تقف جميع الخوارزميات الثلاثة بشكل جيد ضد وابل المتشددين من الاختبارات ، لكن Wyrand و Splitmix أفضل قليلاً من XorShift. (تم اختباره على 30.8 tinyrand عينة)
خوارزميات tinyrand ليست آمنة تشفيرًا ، مما يعني أنه من الممكن تخمين الرقم العشوائي التالي من خلال مراقبة سلسلة من الأرقام. (أو الأرقام السابقة ، لهذه المسألة.) إذا كنت بحاجة إلى CSPRNG قوية ، فمن المقترح بشدة أن تذهب مع rand . CSPRNGs عمومًا أبطأ كثيرًا ومعظم الناس لا يحتاجون إلى واحدة.
cargo add tinyrand مطلوب مثيل Rand لإنشاء أرقام. هنا ، نستخدم StdRand ، وهو الاسم المستعار لـ RNG الافتراضي/الموصى به. (تم تعيينه حاليًا على Wyrand ، ولكن قد يتغير في المستقبل.)
use tinyrand :: { Rand , StdRand } ;
let mut rand = StdRand :: default ( ) ;
for _ in 0 .. 10 {
let num = rand . next_u64 ( ) ;
println ! ( "generated {num}" ) ;
}وبالمثل ، يمكننا إنشاء أعداد من الأنواع الأخرى:
use tinyrand :: { Rand , StdRand } ;
let mut rand = StdRand :: default ( ) ;
let num = rand . next_u128 ( ) ;
println ! ( "generated wider {num}" ) ; تقوم طرق next_uXX بإنشاء أرقام في النطاق غير الموقّع بالكامل من النوع المحدد. في كثير من الأحيان ، نريد رقمًا في نطاق معين:
use tinyrand :: { Rand , StdRand , RandRange } ;
let mut rand = StdRand :: default ( ) ;
let tasks = vec ! [ "went to market" , "stayed home" , "had roast beef" , "had none" ] ;
let random_index = rand . next_range ( 0 ..tasks . len ( ) ) ;
let random_task = tasks [ random_index ] ;
println ! ( "This little piggy {random_task}" ) ; حالة استخدام شائعة أخرى هي توليد bool . قد نرغب أيضًا في تعيين ترجيح للنتائج الثنائية:
use tinyrand :: { Rand , StdRand , Probability } ;
let mut rand = StdRand :: default ( ) ;
let p = Probability :: new ( 0.55 ) ; // a slightly weighted coin
for _ in 0 .. 10 {
if rand . next_bool ( p ) {
// expect to see more heads in the (sufficiently) long run
println ! ( "heads" ) ;
} else {
println ! ( "tails" ) ;
}
}هناك أوقات نحتاج فيها إلى النوم لخيطنا لفترة من الوقت ، في انتظار حالة ما. عندما تنام العديد من الخيوط ، يوصى عمومًا بالتراجع بشكل عشوائي لتجنب التدافع.
use tinyrand :: { Rand , StdRand , RandRange } ;
use core :: time :: Duration ;
use std :: thread ;
use tinyrand_examples :: SomeSpecialCondition ;
let mut rand = StdRand :: default ( ) ;
let condition = SomeSpecialCondition :: default ( ) ;
let base_sleep_micros = 10 ;
let mut waits = 0 ;
while !condition . has_happened ( ) {
let min_wait = Duration :: ZERO ;
let max_wait = Duration :: from_micros ( base_sleep_micros * 2u64 . pow ( waits ) ) ;
let random_duration = rand . next_range ( min_wait..max_wait ) ;
println ! ( "backing off for {random_duration:?}" ) ;
thread :: sleep ( random_duration ) ;
waits += 1 ;
} استدعاء Default::default() على Rand يقوم بتهيئة بذرة ثابتة. هذا أمر رائع للتكرار ولكنه يؤدي إلى نفس المدى للأرقام "العشوائية" ، وهو ما لا يحتاجه معظم الناس.
tinyrand هو قفص no_std ، وللأسف ، لا توجد طريقة جيدة ومحمولة لتوليد إنتروبيا عندما لا يمكن للمرء أن يضع افتراضات حول النظام الأساسي الأساسي. في معظم التطبيقات ، قد لا يكون المرء على مدار الساعة ، ولكن شيء تافهة مثل SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) قد لا يكون متاحًا دائمًا.
إذا كان لديك مصدر إنتروبيات تحت تصرفك ، فيمكنك أن تبهر Rrnd على النحو التالي:
use tinyrand :: { Rand , StdRand , Seeded } ;
let seed = tinyrand_examples :: get_seed_from_somewhere ( ) ; // some source of entropy
let mut rand = StdRand :: seed ( seed ) ;
let num = rand . next_u64 ( ) ;
println ! ( "generated {num}" ) ; قد تفكر أيضًا في استخدام getrandom ، وهي طريقة متعددة المنصات لاسترداد بيانات الإنتروبيا.
إذا لم يهتم المرء بـ no_std ، فلا ينبغي أن يلتزم بقيوده. للبذور من ساعة النظام ، يمكنك الاشتراك في std :
cargo add tinyrand-std الآن ، لدينا ClockSeed تحت تصرفنا ، والتي تنفذ أيضًا سمة Rand . يستمد ClockSeed u64 من خلال Xoring 64 بت من الطابع الزمني النانوي (من SystemTime ) مع 64 بت أقل. هذا ليس مناسبًا للاستخدام التشفير ولكنه سيكون كافياً لمعظم التطبيقات للأغراض العامة.
use tinyrand :: { Rand , StdRand , Seeded } ;
use tinyrand_std :: clock_seed :: ClockSeed ;
let seed = ClockSeed :: default ( ) . next_u64 ( ) ;
println ! ( "seeding with {seed}" ) ;
let mut rand = StdRand :: seed ( seed ) ;
let num = rand . next_u64 ( ) ;
println ! ( "generated {num}" ) ; يتضمن صندوق tinyrand-std أيضًا تنفيذ Rand المصنوع من الخيوط المحلية:
use tinyrand :: Rand ;
use tinyrand_std :: thread_rand ;
let mut rand = thread_rand ( ) ;
let num = rand . next_u64 ( ) ;
println ! ( "generated {num}" ) ; قد يكون من الصعب تحقيق تغطية اختبار جيدة في بعض الأحيان ؛ مضاعفة لذلك عندما تعتمد التطبيقات على العشوائية أو مصادر أخرى من nondeterminism. يأتي tinyrand مع RNG وهمية توفر تحكمًا دقيقًا في تنفيذ الكود الخاص بك.
يستخدم Mock صناديق alloc ، لأنه يتطلب تخصيص الكومة للإغلاق. على هذا النحو ، يتم توزيع الوهمية على أنها حزمة اختيار:
cargo add tinyrand-alloc على المستوى الشعبي ، يتم تكوين Mock وهمية مع حفنة من المندوبين . المندوب هو إغلاق يتم استدعاؤه من قبل وهمية عندما يتم استدعاء طريقة سمة معينة من قبل النظام قيد الاختبار. يحتفظ Mock أيضًا بحالة استدعاء داخلية تتتبع عدد المرات التي تم فيها ممارسة مندوب معين. لذلك ، لا يمكنك فقط السخرية من سلوك سمة Rand ، ولكن أيضًا التحقق من عدد الأنواع التي تم استدعاء مجموعة معينة من طرق السمات ذات الصلة.
يتم تحديد المندوبين في حالة الاختبار ، بينما يتم تمرير مثيل Mock إلى النظام قيد الاختبار كتطبيق Rand . حاليًا ، يتم دعم ثلاثة أنواع مندوبة:
FnMut(&State) -> u128 -تم الاحتجاج به عندما يتم استدعاء إحدى طرق next_uXX() على النفخ. ( uXX كونه واحدًا من u16 أو u32 أو u64 أو u128 أو usize .) يعيد المندوب الرقم "العشوائي" التالي ، والذي قد يصل إلى 128 بت. تم تصميم العرض لاستيعاب u128 - أوسع نوع تدعمه Rand . إذا تم طلب أحد أنواع الأضيق ، فإن النهبة ببساطة تُرجع البتات السفلية. (على سبيل المثال ، بالنسبة لـ u32 ، يتم اقتطاع القيمة السهلة باستخدام as u32 أسفل الغطاء.)FnMut(Surrogate, Probability) -> bool -تم الاحتجاج به عند استدعاء طريقة next_bool(Probability) .FnMut(Surrogate, u128) -> u128 -عند استدعاء next_lim أو next_range . بدءًا من الأساسيات المطلقة ، دعنا نسخر من next_uXX() لإرجاع ثابت. سنتحقق بعد ذلك من عدد المرات التي تم فيها استدعاء وهمية.
use tinyrand :: Rand ;
use tinyrand_alloc :: Mock ;
let mut rand = Mock :: default ( ) . with_next_u128 ( |_| 42 ) ;
for _ in 0 .. 10 {
assert_eq ! ( 42 , rand.next_usize ( ) ) ; // always 42
}
assert_eq ! ( 10 , rand.state ( ) .next_u128_invocations ( ) ) ; على الرغم من أنها بسيطة بشكل محرج ، فإن هذا السيناريو شائع في الواقع. يمكن تحقيق الشيء نفسه مع وظيفة fixed(uXX) .
use tinyrand :: Rand ;
use tinyrand_alloc :: { Mock , fixed } ;
let mut rand = Mock :: default ( ) . with_next_u128 ( fixed ( 42 ) ) ;
assert_eq ! ( 42 , rand.next_usize ( ) ) ; // always 42نظرًا لأن المندوبين عبارة عن إغلاق منتظم ، يمكننا ربط المتغيرات في النطاق المرفق. هذا يعطينا سيطرة غير محدودة تقريبًا على سلوكنا الوهمي.
use tinyrand :: Rand ;
use tinyrand_alloc :: Mock ;
use core :: cell :: RefCell ;
let val = RefCell :: new ( 3 ) ;
let mut rand = Mock :: default ( ) . with_next_u128 ( |_| * val . borrow ( ) ) ;
assert_eq ! ( 3 , rand.next_usize ( ) ) ;
// ... later ...
* val . borrow_mut ( ) = 17 ;
assert_eq ! ( 17 , rand.next_usize ( ) ) ;يمكن إعادة تعيين المندوب في أي وقت ، حتى بعد إنشاء الوهمية وممارستها:
use tinyrand :: Rand ;
use tinyrand_alloc :: { Mock , fixed } ;
let mut rand = Mock :: default ( ) . with_next_u128 ( fixed ( 42 ) ) ;
assert_eq ! ( 42 , rand.next_usize ( ) ) ;
rand = rand . with_next_u128 ( fixed ( 88 ) ) ; // the mock's behaviour is now altered
assert_eq ! ( 88 , rand.next_usize ( ) ) ; يأخذ توقيع مندوب next_u128 مرجعًا State ، والذي يلتقط عدد المرات التي تم فيها استدعاء وهمية. (يتم زيادة العد فقط بعد اكتمال الاحتجاج.) دعنا نكتب وهمية تُرجع رقمًا "عشوائيًا" مشتقًا من حالة الاحتجاج.
use tinyrand :: Rand ;
use tinyrand_alloc :: Mock ;
let mut rand = Mock :: default ( ) . with_next_u128 ( |state| {
// return number of completed invocations
state . next_u128_invocations ( ) as u128
} ) ;
assert_eq ! ( 0 , rand.next_usize ( ) ) ;
assert_eq ! ( 1 , rand.next_usize ( ) ) ;
assert_eq ! ( 2 , rand.next_usize ( ) ) ; هذا مفيد عندما نتوقع أن يتم استدعاء وهمية عدة مرات ويجب أن يعيد كل الاحتجاج نتيجة مختلفة. يمكن تحقيق نتيجة مماثلة من خلال وظيفة counter(Range) ، والتي تدور من خلال مجموعة محددة من الأرقام ، واللف بسهولة على الحدود:
use tinyrand :: Rand ;
use tinyrand_alloc :: { Mock , counter } ;
let mut rand = Mock :: default ( ) . with_next_u128 ( counter ( 5 .. 8 ) ) ;
assert_eq ! ( 5 , rand.next_usize ( ) ) ;
assert_eq ! ( 6 , rand.next_usize ( ) ) ;
assert_eq ! ( 7 , rand.next_usize ( ) ) ;
assert_eq ! ( 5 , rand.next_usize ( ) ) ; // start again من خلال توفير مندوب next_u128 فقط ، يمكننا التأثير على نتيجة كل طريقة أخرى في سمة Rand ، لأنها جميعها تستمد من نفس مصدر العشوائية وسوف نسمي في النهاية مندوبنا تحت الغطاء ... من الناحية النظرية! في الممارسة العملية ، الأمور أكثر تعقيدًا.
يتم دعم أساليب Rand المشتقة ، مثل next_bool(Probability) و next_lim(uXX) و next_range(Range) بتوزيعات احتمالية مختلفة. next_bool ، على سبيل المثال ، يسحب من توزيع Bernoulli ، في حين يستخدم next_lim و next_range توزيعًا موحدًا موحدًا مع طبقة مُقالة إضافية. علاوة على ذلك ، فإن التعيين بين التوزيعات المختلفة هو تفاصيل تنفيذ داخلية تخضع للتغيير. تحتوي طبقة الإنصاف وحدها على عدة تطبيقات ، محسّنة لأنواع من العروض المختلفة. وبعبارة أخرى ، فإن التعيينات من next_u128 إلى next_bool و next_lim و next_range وغير التافهة ؛ إنه ليس شيئًا تريد أن تسخر منه بدون آلة حاسبة وبعض المعرفة بالحساب المعياري.
لحسن الحظ ، يتيح لنا Rand "تجاوز" وظائف التعيين هذه. هذا هو المكان الذي يأتي فيه المندوبين الآخرون. في المثال التالي ، نسخر من نتائج next_bool .
use tinyrand :: { Rand , Probability } ;
use tinyrand_alloc :: Mock ;
let mut rand = Mock :: default ( ) . with_next_bool ( |_ , _| false ) ;
if rand . next_bool ( Probability :: new ( 0.999999 ) ) {
println ! ( "very likely" ) ;
} else {
// we can cover this branch thanks to the magic of mocking
println ! ( "very unlikely" ) ;
} يتم تسليم مندوب next_bool بنية Surrogate ، وهو تطبيق Rand وحارس حالة الاحتجاج. يتيح لنا البديل استخلاص bool S ، مثل:
use tinyrand :: { Rand , Probability } ;
use tinyrand_alloc :: Mock ;
let mut rand = Mock :: default ( ) . with_next_bool ( |surrogate , _| {
surrogate . state ( ) . next_bool_invocations ( ) % 2 == 0
} ) ;
assert_eq ! ( true , rand.next_bool ( Probability ::new ( 0.5 ) ) ) ;
assert_eq ! ( false , rand.next_bool ( Probability ::new ( 0.5 ) ) ) ;
assert_eq ! ( true , rand.next_bool ( Probability ::new ( 0.5 ) ) ) ;
assert_eq ! ( false , rand.next_bool ( Probability ::new ( 0.5 ) ) ) ;يتيح البديل أيضًا للمندوب استدعاء الأساليب السخرية من داخل الوهمية.
يتم استخدام المندوب الأخير للسخرية من أساليب next_lim و next_range ، بسبب التماثل. تحت الغطاء ، مندوب next_range إلى next_lim ، بحيث بالنسبة لأي زوج من حدود الحد ( M ، N ) ، M < N ، next_range(M..N) = M + next_lim(N - M) . هكذا يسخر كل شيء في الممارسة:
use tinyrand :: { Rand , RandRange } ;
use tinyrand_alloc :: Mock ;
enum Day {
Mon , Tue , Wed , Thu , Fri , Sat , Sun
}
const DAYS : [ Day ; 7 ] = [ Day :: Mon , Day :: Tue , Day :: Wed , Day :: Thu , Day :: Fri , Day :: Sat , Day :: Sun ] ;
let mut rand = Mock :: default ( ) . with_next_lim_u128 ( |_ , _| 6 ) ;
let day = & DAYS [ rand . next_range ( 0 .. DAYS . len ( ) ) ] ;
assert ! ( matches! ( day, Day :: Sun ) ) ; // always a Sunday
assert ! ( matches! ( day, Day :: Sun ) ) ; // yes!!!tinyrand ؟ يصف هذا القسم بإيجاز نهج اختبار tinyrand . يستهدف أولئك الذين -
يتم تقسيم عملية اختبار tinyrand إلى أربع مستويات:
tinyrand . بمعنى آخر ، يتم ممارسة كل سطر من الكود مرة واحدة على الأقل ، يتم دعم التوقعات الأساسية ومن المحتمل ألا تكون هناك عيوب تافهة.tinyrand . هذه اختبارات فرضية رسمية تفترض أن المصدر عشوائي (الفرضية الفارغة) ، وابحث عن أدلة لتبديد هذا الافتراض (الفرضية البديلة).لا تهدف اختبارات الوحدة إلى تأكيد الصفات العددية ؛ فهي وظيفية بحتة في الطبيعة. وتشمل الأهداف -
tinyrand على الفلسفة أنه إذا لم يتم ممارسة سطر الكود بشكل كبير ، فيجب إزالته. لا توجد استثناءات لهذه القاعدة.true مقابل false في توليد bool s. إن وظائف التعيين من التوزيع الموحد إلى واحد مخصص غير تافهة وتتطلب طبقة محدودة. يستخدم tinyrand أساليب التنسيق المختلفة اعتمادًا على عرض الكلمة. الغرض من اختبارات تحويل المجال هو التحقق من أن هذه الوظيفة تعمل كما هو متوقع وأن يتم أخذ عينات الرفض. لا يتحقق من الخصائص العددية للإنقاذ. تُستخدم المعايير الاصطناعية لممارسة المسارات الساخنة لـ tinyrand PRNGs ، ومقارنة النتائج بمكتبات الأقران. تختبر المعايير توليد الأرقام بأطوال الكلمات المختلفة ، والتحويلات/التنسيق وتوليد bool الموزونة. يتم أيضًا تضمين مجموعة فرعية من هذه المعايير في اختبارات CI ، مما يجعل من الأسهل قليلاً مقارنة أداء tinyrand عبر إصدارات الالتزام.
يأتي tinyrand مع جناح اختبار إحصائي متكامل ، مستوحى من أمثال Diehard و Dieharder و NIST SP 800-22. جناح tinyrand هو أصغر بكثير من أي من هذه الاختبارات ؛ لا تتمثل القصد في تكرار العمل الكبير بالفعل الذي يمكن الوصول إليه بسهولة في هذا المجال ، ولكن إنشاء شبكة أمان فعالة للغاية في اكتشاف الحالات الشاذة الشائعة وسريعة بما يكفي لتشغيلها في كل التزام.
يتم تضمين الاختبارات التالية.
Rand من خلال إخفاء قيمة جزء واحد ، والتحقق من أن عدد المرات التي يتم تعيين BIT على 1 ضمن النطاق المتوقع. لكل محاكمة لاحقة ، يتم تحويل القناع بواسطة واحد إلى اليسار ويتم إعادة اختبار الفرضية. يستمر الاختبار على عدة دورات ؛ كل دورة تضم 64 تجربة برنولي (واحدة لكل بت من u64 ).bool مع احتمال مختار من كلمة غير موقعة 64 بت. يشتمل الاختبار على سلسلة من تجارب Bernoulli مع ترجيح مختلف (تم اختياره عشوائيًا) في كل تجربة ، ومحاكاة تقلبات العملة المعدنية. داخل كل تجربة ، يؤكد H0 أن المصدر عشوائي. (أي ، يقع عدد "الرؤوس" ضمن فاصل مقبول إحصائياً.)u64 S في تجارب منفصلة. في كل تجربة ، نفترض أن قيم البتات الفردية هي IID مع احتمال 0.5 ، والتحقق من أن عدد المرات التي يتم تعيين البت على 1 ضمن النطاق المتوقع. لمصدر عشوائي ، يتبع عدد 1s (و 0s) عملية Bernoulli. يتم ممارسة كل اختبارات من tinyrand ليس فقط ضد PRNGs الخاصة بها ، ولكن أيضًا ضد التطبيقات المعيبة عن قصد ، والتي تستخدم للتحقق من فعالية الاختبار. يجب أن تفشل الاختبارات باستمرار في رفض H0 ل PRNGs الصحيحة وقبول H1 للمرات المعيبة.
الاختبارات الإحصائية هي نفسها مصنفة من قيم عشوائية. يتم استخدام العشوائية لبذرة PRNGs قيد الاختبار (كل تجربة مصنفة بشكل مستقل) ، وتعيين أوزان لتجارب برنولي ، وتحديد نطاقات عدد صحيح لاختبار وظائف التحويل والقيام ، وقيم التحكم في اختبار الاصطدام ، وما إلى ذلك. نستخدم حزمة rand كتحكم PRNG بحيث لا يمكن للعيوب في tinyrand تخريب اختبار عن غير قصد بطريقة تخفي نفسها. يتم زرع الاختبارات بحيث يبدو أنها في رحلة عشوائية من خلال مساحة المعلمة ، فإن اختيارهم للمعلمات أمر حتمي تمامًا وبالتالي قابل للتكرار. هذا أمر ضروري بسبب إمكانية خطأ من النوع الأول (رفض الفرضية الفارغة بشكل غير صحيح) ، والتي يجب ألا يُسمح لها بحدوثها بشكل متقطع ، وخاصة في بيئات CI. بمعنى آخر ، لا يمكن ترك اختبار العشوائية للصدفة .
تتمثل إحدى طرق اختبار فرضية العشوائية في تحديد مجموعة من المعلمات (على سبيل المثال ، نطاق توليد عدد صحيح M .. N أو احتمال الحصول على true من توزيع Bernoulli) وأداء على المدى الطويل ، والبحث عن الحالات الشاذة في عينة عشوائية كبيرة . الأساس المنطقي هو أنه كلما كانت العينة أكبر ، زاد احتمال احتوائها على شذوذ يمكن اكتشافه. هذا عمومًا ليس فعالًا جدًا في اكتشاف أنواع معينة من الحالات الشاذة التي قد تؤثر على PRNGs فقط في ظل ظروف محددة للغاية. على سبيل المثال ، قد لا تزال وظيفة الإنصاف المكتوبة بشكل جيد تعمل بشكل جيد بالنسبة لمعظم نطاقات عدد صحيح صغير وحتى بعضها الكبير (تلك القريبة من قوى اثنين). إذا اختار الاختبار المعلمات بشكل غير موات ، فقد لا يجد الحالات الشاذة بغض النظر عن مدى اختباراتها بشكل شامل لتلك المعلمات.
تتمثل طريقة أفضل بكثير في اختبار PRNG في إدخال التنوع في نظام الاختبار - إجراء عدد كبير من التجارب الصغيرة مع معلمات مختلفة بدلاً من تجربة كبيرة جدًا. هذا هو بالضبط ما تقوم به اختبارات tinyrand الإحصائية - إجراء العديد من التجارب مع معلمات محددة بشكل عشوائي (ولكن من الناحية المحددة). هذا يعرض على الفور مشكلة المقارنات المتعددة. النظر في prng مثالية prng. سيؤدي ذلك في كثير من الأحيان إلى إنشاء أرقام ستظهر "عشوائيًا" وفقًا لبعض التدابير المتفق عليها. ولكن في بعض الأحيان ، سوف ينتج إخراجًا سيظهر غير عشوائي بنفس التدبير. حتى المصدر المثالي سيؤدي إلى إنتاج طويل جدًا من تلك أو الأصفار ، على سبيل المثال. في الواقع ، فإن الفشل في القيام بذلك سيجعله غير عشوائي. لسوء الحظ ، سيؤدي ذلك إلى إنتاج قيمة p ستفشل حتى الاختبار الأكثر استرخاء ... في مرحلة ما. هذه مشكلة لاختبار الفرضيات الفردية ، لكنها تفاقمت نسبيًا في اختبار الفرضيات المتعددة.
تتناول اختبارات tinyrand المدمجة هذه المشكلة باستخدام طريقة تصحيح Holm-Bonferroni المتسلسلة. تصحيح Holm-Bonferroni يمنع الأخطاء من النوع الأول مع الحفاظ على القوة الإحصائية الجيدة-قمع أخطاء النوع الثاني. يبدو أنه يعمل بشكل جيد لتلبية احتياجات tinyrand ، خاصةً رؤية أن تجارب الأرقام يتم الاحتفاظ بها بشكل عام في نطاق 100-1000. (تم تصميم اختبارات tinyrand لتكون سريعة للغاية ، مما يضع حدًا عمليًا على عدد التجارب - من الناحية المثالية ، يجب أن تكتمل جميع الاختبارات الإحصائية في غضون بضع ثوان حتى يتم تكليفها كجزء من تدفق التطوير الروتيني.)
جناح اختبار Dieharder يمتد بطارية الاختبارات الأصلية من Marsaglia. يتم تجميعه بعدد كبير من الاختبارات ويستغرق وقتًا طويلاً (حوالي ساعة واحدة) لإكماله. لدى tinyrand فائدة لضخ الناتج العشوائي إلى Dieharder ، والذي يتم تشغيله عادة على أساس مخصص. يجب تشغيل بطارية Dieharder عندما تخضع PRNG لتغيير مادي ، وهو أمر نادر الحدوث - بمجرد تنفيذ خوارزمية PRNG ، يبقى عمومًا دون مساس ما لم يتم إعادة تمثيله أو العثور على بعض العيوب. يمكن القول أن Dieharder أكثر فائدة لبناء واختبار PRNGs التجريبية مع tinyrand . المستويات الثلاثة الأخرى من الاختبارات كافية للحفاظ على حزمة tinyrand .
لتشغيل tinyrand ضد Dieharder:
cargo run --release --bin random -- wyrand 42 binary 1T | dieharder -g 200 -a يستخدم الأمر أعلاه Wyrand PRNG ، المصنوع من الرقم 42 ، مما يولد إخراج ثنائي أكثر من 1 تريليون كلمات 64 بت. يتم ضخها stdout إلى dieharder . (في الممارسة العملية ، سوف يستهلك Dieharder أقل من 31 مليار عدد.)
كلمة تحذير: ليس لدى Dieharder آلية للتعامل مع أخطاء النوع الأول في اختبار الفرضيات المتعددة - جزئيًا لأن الاختبارات تختلف في النوع ، وليس فقط في المعلمات. يحد المتشددين من اختبار الفرضية إلى نطاق الاختبار الفردي ؛ لا توجد فرضية شاملة تصنف PRNG على أنها ملائمة أو غير صالحة بناءً على عدد الاختبارات التي تم تمريرها ، أو يقوم بضبط مستوى الثقة في حساب أخطاء النوع الأول.