tinyrand
Lightweight RNG 사양 및 Rust의 몇 가지 초고속 구현. tinyrand
는 no_std
이며 힙 할당자를 사용하지 않습니다.
tinyrand
?std
필요하지 않습니다. 즉, 마이크로 컨트롤러 및 베어 메탈 (OS) 환경에서 실행됩니다.Mock
함께 제공됩니다. 즉, 코드 커버리지에 관심이있는 경우.아래는 몇 가지 주목할만한 PRNG를 비교 한 것입니다.
prng | 연산 | 대역폭 (GB/S) | |
---|---|---|---|
rand | Chacha12 | 2.4 | |
tinyrand | 분할 믹스 | 6.5 | |
tinyrand | xorshift | 6.7 | |
fastrand | Wyrand | 7.5 | |
tinyrand | Wyrand | 14.6 |
TL; DR : tinyrand
는 fastrand
보다 2 배 빠르며 rand
보다 6 배 빠릅니다.
특정 PRNG가 좋은지 확실하게 말하는 것은 불가능합니다. 대답은 확률 론적입니다. 세 가지 알고리즘은 모두 테스트의 다이 하더 사격에 대해 잘 어울리지 만 Wyrand와 Splitmix는 Xorshift보다 약간 좋습니다. 이는 tinyrand
충분히 무작위로 나타나는 숫자를 생성하고 대부분의 응용 분야에서 사용하기에 적합한 숫자를 생성하는 것을 의미합니다.
tinyrand
알고리즘은 암호화 적으로 안전하지 않으므로 일련의 숫자를 관찰하여 다음 랜덤 번호를 추측 할 수 있습니다. (또는 그 문제에 대한 앞의 숫자.) 강력한 CSPRNG가 필요한 경우 rand
와 함께 갈 것을 강력하게 제안합니다. CSPRNGS는 일반적으로 훨씬 느리며 대부분의 사람들은 필요하지 않습니다.
cargo add tinyrand
숫자를 생성하려면 Rand
인스턴스가 필요합니다. 여기에서는 기본/권장 RNG의 별칭 인 StdRand
사용합니다. (현재 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 ;
}
Rand
에서 Default::default()
호출하면 일정한 시드로 초기화됩니다. 이것은 반복성에 적합하지만 동일한 "무작위"숫자를 실행하여 대부분의 사람들이 필요로하지 않습니다.
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
64 비트가 낮은 64 비트의 64 비트 ( SystemTime
에서)를 Xoring하여 u64
도출합니다. 암호화 사용에는 적합하지 않지만 대부분의 일반 목적 애플리케이션에는 충분합니다.
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
Crate에는 시드 된 스레드-로컬 Rand
구현도 포함됩니다.
use tinyrand :: Rand ;
use tinyrand_std :: thread_rand ;
let mut rand = thread_rand ( ) ;
let num = rand . next_u64 ( ) ;
println ! ( "generated {num}" ) ;
좋은 테스트 범위는 때때로 달성하기 어려울 수 있습니다. 적용이 무작위성 또는 다른 비 결정 주의원에 의존 할 때 이중으로. tinyrand
에는 코드 실행에 대한 세밀한 제어를 제공하는 Mock RNG가 제공됩니다.
이 조롱은 힙 클로저 할당이 필요하기 때문에 alloc
상자를 사용합니다. 따라서 모의는 옵트 인 패키지로 배포됩니다.
cargo add tinyrand-alloc
풀뿌리 수준에서 Mock
소수의 대표 와 구성된 구조물입니다. 대의원은 테스트중인 시스템에 의해 특정 특성 방법을 호출 할 때 모의에 의해 호출되는 폐쇄입니다. 이 조롱은 또한 특정 대의원이 행사 한 횟수를 추적하는 내부 호출 상태를 유지합니다. 따라서 Rand
특성의 동작을 조롱 할뿐만 아니라 관련 특성 그룹의 특정 그룹이 호출 된 유형의 수를 확인할 수 있습니다.
대의원은 테스트 사례에 의해 지정되며 모의 인스턴스는 Rand
구현으로 테스트중인 시스템으로 전달됩니다. 현재 세 가지 대표 유형이 지원됩니다.
FnMut(&State) -> u128
-Mock에서 next_uXX()
메소드 중 하나가 호출되면 호출됩니다. ( uXX
는 u16
, u32
, u64
, u128
또는 usize
중 하나입니다.) 대의원은 다음 "랜덤"숫자를 반환하며, 이는 최대 128 비트가 될 수 있습니다. 너비는 Rand
가 지원하는 가장 넓은 유형 인 u128
수용하도록 설계되었습니다. 좁은 유형 중 하나가 요청되면 모의는 단순히 더 낮은 비트를 반환합니다. (예 : 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
특성의 다른 모든 방법의 결과에 영향을 줄 수 있습니다. 왜냐하면 그들은 모두 같은 임의의 원천에서 파생되어 결국 우리의 대의원을 후드 아래에서 호출 할 것이기 때문입니다. 실제로, 상황은 훨씬 더 복잡합니다.
next_bool(Probability)
, next_lim(uXX)
및 next_range(Range)
와 같은 파생 된 Rand
방법은 다른 확률 분포에 의해 뒷받침됩니다. 예를 들어 next_bool
은 Bernoulli 분포에서 나오는 반면 next_lim
및 next_range
추가 디비어링 레이어와 함께 스케일 균일 분포를 사용합니다. 또한, 다양한 분포 사이의 매핑은 변경 될 수있는 내부 구현 세부 사항이다. Debiasing Layer만으로는 다양한 구현이 있으며 다양한 폭의 유형에 최적화되었습니다. 다시 말해서, 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
을 도출 할 수있게 해줍니다.
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
테스트 프로세스는 4 단계로 나뉩니다.
tinyrand
의 원소 정신을 주장하는 데 사용됩니다. 다시 말해, 모든 코드 라인은 적어도 한 번은 행사되며, 기본 기대치가지지되고 사소한 결함이 없을 것 입니다 .tinyrand
구성하는 PRNG의 특정 특성을 검증합니다. 이것들은 소스가 무작위 (귀무 가설)라고 가정하는 공식적인 가설 테스트이며,이 가정 (대체 가설)을 없애는 증거를 찾습니다.단위 테스트는 수치 적 특성을 주장하는 것을 목표로하지 않습니다. 그들은 순전히 기능적입니다. 목표는 다음을 포함합니다.
tinyrand
코드 라인을 행사하지 않으면 제거되어야한다는 철학을 기반으로합니다. 이 규칙에는 예외가 없습니다.bool
생성에서 true
결과와 false
의 가중치. 균일 한 분포에서 사용자 정의 분포로의 매핑 기능은 사소하지 않으며 토론 층이 필요합니다. tinyrand
단어 너비에 따라 다른 Debiasing 방법을 사용합니다. 도메인 변환 테스트의 목적은이 기능이 예상대로 작동하고 거부 샘플링이 진행되고 있는지 확인하는 것입니다. 그러나 토론의 수치 적 특성을 확인하지는 않습니다. 합성 벤치 마크는 결과를 피어 라이브러리와 비교하여 tinyrand
PRNG의 뜨거운 경로를 운동하는 데 사용됩니다. 벤치 마크는 다양한 단어 길이, 변환/디아 싱 및 가중 bool
의 생성에서 숫자 생성을 테스트합니다. 이러한 벤치 마크의 하위 집합은 CI 테스트에도 포함되어있어 Commit 버전에서 tinyrand
의 성능을 더 쉽게 비교할 수 있습니다.
tinyrand
Diehard, Dieharder 및 NIST SP 800-22와 같은 사람들에서 영감을 얻은 통합 통계 테스트 제품군과 함께 제공됩니다. tinyrand
Suite는 이러한 테스트 중 어느 것보다 훨씬 작습니다. 의도는이 영역에서 이미 실질적이고 쉽게 접근 할 수있는 작업을 복제하는 것이 아니라 공통된 이상을 감지하는 데 매우 효과적인 안전망을 만들고 모든 커밋에서 실행하기에 충분히 빠릅니다.
다음 테스트가 포함되어 있습니다.
Rand
인스턴스에서 일련의 Bernoulli 시험을 수행하여 비트가 1로 설정된 횟수가 예상 범위 내에 있는지 확인합니다. 각각의 후속 시험에 대해, 마스크는 왼쪽으로 하나씩 이동하고 가설이 다시 테스트됩니다. 테스트는 여러주기에 걸쳐 진행됩니다. 각주기는 64 개의 Bernoulli 시험 ( u64
의 각 비트마다 하나씩)을 포함합니다.bool
얻습니다. 이 테스트는 각 시험마다 다른 (무작위로 선택된) 가중치를 갖는 일련의 베르누이 시험으로 구성되어 코인 플립의 달리기를 시뮬레이션합니다. 각 시험 내에서 H0은 소스가 무작위라고 주장합니다. (즉, '헤드'의 수는 통계적으로 허용되는 간격에 속합니다.)u64
S의 MSB와 LSB 세그먼트를 번갈아 가면서 32 비트 단어로 비트 수를 계산합니다. 각각의 시험에서, 우리는 개별 비트의 값이 0.5의 확률 인 IID라고 가정하여 비트가 1으로 설정된 횟수가 예상 범위 내에 있는지 확인합니다. 임의의 소스의 경우 1 (및 0)의 수는 Bernoulli 프로세스를 따릅니다. tinyrand
의 각 테스트는 자체 PRNG뿐만 아니라 의도적으로 결함이있는 구현에 대해서도 시험의 효능을 검증하는 데 사용됩니다. 테스트는 올바른 PRNG에 대해 일관되게 H0을 거부하지 못하고 결함이있는 경우 H1을 수락해야합니다.
통계 테스트 자체는 임의의 값에서 시드됩니다. 임의성은 시험중인 PRNG를 시드하는 데 사용됩니다 (모든 시험은 독립적으로 시드), Bernoulli 실험에 가중치를 할당하고 변환 기능 및 토론 테스트를위한 정수 범위, 충돌 테스트를위한 제어 값 등을 선택합니다. 우리는 rand
패키지를 Control PRNG로 사용하여 tinyrand
의 결함이 자체적으로 마스킹하는 방식으로 테스트를 부주의하게 파괴 할 수 없도록합니다. 테스트는 파라미터 공간을 통한 임의의 여행에있는 것처럼 보이지만 매개 변수 선택은 전적으로 결정적이므로 반복 가능합니다. 이는 유형 I 오류 가능성 (귀무 가설을 잘못 거부 함)의 가능성으로 인해 필수적이며, 특히 CI 환경에서 간헐적으로 발생하지 않아야합니다. 다시 말해, 무작위성 테스트는 우연히 남을 수 없습니다 .
무작위성 가설을 테스트하는 한 가지 방법은 매개 변수 세트 (예 : 정수 생성 범위 M
.. N
Bernoulli 분포에서 true
얻을 확률)를 선택하고 큰 무작위 샘플에서 이상을 찾는 것입니다. . 이론적 근거는 샘플이 클수록 검출 가능한 이상을 함유 할 가능성이 높다는 것입니다. 이것은 일반적으로 매우 구체적인 조건에서만 PRNG에 영향을 줄 수있는 특정 종류의 이상을 발견하는 데 그다지 효과적이지 않습니다. 예를 들어, 제대로 쓰여진 서면 디비어링 기능은 여전히 대부분의 작은 정수 범위와 일부 큰 범위 (2의 힘에 가까운 것)에서도 잘 수행 될 수 있습니다. 테스트에서 매개 변수를 불리하게 선택하면 해당 매개 변수를 얼마나 철저하게 테스트하든 이상이 변하지 않을 수 있습니다.
PRNG를 테스트하는 훨씬 더 좋은 방법은 테스트 체제에 다양성을 도입하는 것입니다. 이는 하나의 매우 큰 시험이 아닌 다른 매개 변수로 다수의 작은 시험을 수행하는 것입니다. 이것이 바로 tinyrand
통계 테스트가하는 일입니다. 이것은 즉시 다중 비교 문제를 노출시킵니다. 선험적 인 이상적인 prng를 고려하십시오. 합의 된 일부 측정에 따라 "무작위"로 나타날 숫자를 종종 생성합니다. 그러나 때때로, 그것은 같은 척도에 의해 비 랜덤이 나타날 출력을 생성 할 것입니다. 예를 들어 이상적인 소스조차도 매우 장기적인 소스 나 0을 생산할 것입니다. 실제로 그렇게하지 않으면 비 랜덤도하게 될 것입니다. 불행히도, 이것은 어느 시점에서 가장 편안한 테스트조차 실패하는 p- 값을 생성합니다. 이것은 단일 가설 테스트의 문제이지만 다중 가설 테스트에서 비례 적으로 악화됩니다.
tinyrand
내장 테스트는 Holm-Bonferroni 순차 수정 방법을 사용 하여이 문제를 해결합니다. Holm-Bonferroni Correction은 유형 II 오류를 유지하면서 유형 I 오류를 억제하면서 유형 I 오류를 억제합니다. tinyrand
의 요구에 잘 어울리는 것으로 보이며, 특히 숫자 시험이 일반적으로 100-1000 범위에 보관되어 있음을 알 수 있습니다. ( tinyrand
테스트는 매우 빠르도록 설계되었으며, 이는 시험 수에 실질적인 구속력을 갖습니다. 이상적으로는 모든 통계 테스트가 일상적인 개발 흐름의 일부로 의무화되도록 몇 초 안에 완료되어야합니다.)
Dieharder Test Suite는 Marsaglia의 원래 Diehard 배터리를 확장합니다. 많은 수의 테스트와 함께 번들로 완료하는 데 오랜 시간 (~ 1 시간)이 걸립니다. tinyrand
Dieharder에 임의의 출력을 펌핑하는 유틸리티를 가지고 있으며, 이는 일반적으로 임시로 실행됩니다. PRNG가 재료 변경을 겪을 때 Dieharder 배터리를 실행해야합니다. 드문 경우가 드물다. PRNG 알고리즘이 구현되면 일반적으로 리팩토링되거나 일부 결함이 발견되지 않는 한 손길이 닿지 않습니다. Dieharder는 tinyrand
와 실험용 PRNG를 구축하고 테스트하는 데 더 유용 할 것입니다. 다른 3 단계 테스트는 tinyrand
패키지의 유지에 충분합니다.
Dieharder에 대해 tinyrand
운영하려면 :
cargo run --release --bin random -- wyrand 42 binary 1T | dieharder -g 200 -a
위의 명령은 숫자 42로 시드 된 Wyrand PRNG를 사용하여 1 조 64 비트 단어 이상의 이진 출력을 생성합니다. stdout
은 dieharder
로 펌핑됩니다. (실제로 Dieharder는 310 억에 달하는 숫자를 소비 할 것입니다.)
주의 사항 : Dieharder는 여러 가설 테스트에서 유형 I 오류를 처리하는 메커니즘이 없습니다. 부분적으로 테스트가 매개 변수뿐만 아니라 유형이 다르기 때문입니다. Dieharder는 가설 테스트를 개별 테스트의 범위로 제한합니다. PRNG를 전달 된 테스트 수에 따라 적합하거나 부적합한 것으로 분류하거나 유형 I 오류를 설명하도록 신뢰도를 조정하는 가장 중요한 가설은 없습니다.