Skip to content

Instantly share code, notes, and snippets.

@battlecoder
Forked from unprovable/rand-period-test.c
Last active December 31, 2017 20:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save battlecoder/d89d6ca3abbb91f1ab739e51a6cedfe4 to your computer and use it in GitHub Desktop.
Save battlecoder/d89d6ca3abbb91f1ab739e51a6cedfe4 to your computer and use it in GitHub Desktop.
Random Periodicity Test Code for arduino (compiled in Arduino IDE)
/*
* Test sketch based on rand-period-test.c by @unprovable
* His sketch shown an anomaly with Arduino's PRNG, in which the LCG period seems to be unreliable.
* Also the function seems to be quite slow; iterating over the stream until we get back to the beginning
* takes 199340888ms (55.3724689 hours). It takes 1.5 minutes (approx) to generate 1M numbers.
* So I decided to repeat the test with a textbook implementation of a standard LCG to see if we can get a
* reliable generator with a stable period (and hopefully faster runtime) under the same conditions.
* In my test, this script takes ~47 seconds each 1M numbers, and 103345725 ms (28.707146 hours) in total,
* with a period that matches the theoretical expected value of 7FFFFFFF, so if you are going to do random
* with an arduino, even a regular standard LCG implementation is way better than what you get out of the
* box.
* NOTE: Tests performed on an Arduino Nano (Atmega328p processor) @ 16Mhz.
*/
long rand_i, rand_j, rand_k;
unsigned long i = 0, j = 0, k = 0;
long startTime;
long lastTime;
long now;
unsigned long lcg_seed = 0x50000L; // Could be any value
unsigned long rand2(){
lcg_seed = (lcg_seed * 1103515245L + 12345L) % 2147483648L;
return lcg_seed;
}
void setup() {
// put your setup code here, to run once:
rand_i = rand2();
rand_j = rand2();
rand_k = rand2();
Serial.begin(57600);
while (!Serial) {}
Serial.print("starting num rand_i: "); Serial.println(rand_i, HEX);
Serial.print("starting num rand_j: "); Serial.println(rand_j, HEX);
Serial.print("starting num rand_k: "); Serial.println(rand_k, HEX);
pinMode(LED_BUILTIN, OUTPUT);
Serial.print("using rand_k = ");Serial.println(rand_k);
startTime = millis();
lastTime = startTime;
}
void loop() {
// put your main code here, to run repeatedly:
if ((i % 1000000) == 0) {
now = millis();
Serial.print("Up to ");
Serial.print(i);
Serial.print(" iterations in ");
Serial.print((long)(now - lastTime), DEC);
Serial.println(" ms");
lastTime = now;
}
if (rand2() == rand_k) {
now = millis();
Serial.print("MATCH!! We got a match on "); Serial.print(rand_k); Serial.print(" in "); Serial.print(i, HEX); Serial.println(" operations.");
//i = 0;
while(true){
Serial.print("MATCH!! We got a match on "); Serial.print(rand_k); Serial.print(" in "); Serial.print(i, HEX); Serial.println(" operations.");
Serial.print("-- It took ");
Serial.print((long)(now - startTime), DEC);
Serial.println(" ms");
digitalWrite(LED_BUILTIN, HIGH);
delay(50000);
digitalWrite(LED_BUILTIN, LOW);
delay(500);
}; // stop the duino so we can see what the magic number is :-P Keep printing in case the serial port goes to sleep...
}
i++;
}
@battlecoder
Copy link
Author

battlecoder commented Nov 24, 2017

If you are wondering how this code compares to unprovable's sketch but you don't want to run a diff: This sketch is exactly the same, but it uses a standard LCG (implemented in rand2()) instead of Arduino's random().

It also has a global time counter to know how much time it takes to run this whole thing, which is something I also added to my local copy of his sketch when I ran the test on my Arduino. That's how I know how much time it took, and was able to compare.

If you run mine and unprovable's sketch on an Arduino other than a Nano @ 16Mhz, let me know! It would be quite interesting to know what the performance is like, and what result you get, on other Arduinos, with different processors and/or clock speeds.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment