RandomSeed reference only suggests using analogread to seed random numbers. I don't have a spare pin and need to generate random numbers with a different "seed" or random input.
Will a call to millis() provide a suitable random input for randomseed?
No. If it's called at the same point in the program, it will give you the same seed every time you re-start the program.
If have buttons or switches and human-input you can run a loop generating un-seeded random numbers in a fast-loop, and then when a button is pressed, grab the current (unpredictable) number and use that for the seed and break-out of the loop.
Or if there is a button-press every time you need a random number, the same procedure can be used (with random numbers being continuously generated in a loop). With that method you don't need a random seed, or you don't need to seed at all.
The simplest way of ensuring truly random starts for the sequence generator is to use human input, like a button press.
Find a way to free up a pin, connect a button between it and GND, and use INPUT_PULLUP to keep the button pin HIGH until a human pushes the button.
This gives me a different number "every" restart...
void setup() {
randomSeed(analogRead(A0));
Serial.begin(9600);
Serial.print(random(100)+1);
}
void loop() {}
I noticed the Nano tends toward the lower side of random. That is to say, random 1 to 100 will yield more < 50.
It does not work well for me. In addition, there are only 1024 possible start points, of which very few are typically accessed in a fixed setup.
I noticed the Nano tends toward the lower side of random. That is to say, random 1 to 100 will yield more < 50
You undoubtedly have not tested that observation thoroughly. A truly random set of outcomes will only extremely rarely produce exactly half above and half below the midpoint.
random() is actually pretty decent, and behaves as expected. For simple random number generators, the problems that many people perceive are due to their incorrect expectations of the outcome.
The Arduino random() does everything I need, but I can imagine real world applications which need more randomness, so patterns do not emerge (lens grinding, for one).
The other randomness test I did (other than post #4) was to map "random(128) x random(64)" on an OLED. The display was nicely scattered, but more than half of the pixels piled into one corner, toward 0,0. Nothing scientific, just plot random(x), random(y), and let my eyes see the bright blobs.
True randomness does not produce even distribution, rather it creates bunches.
That is a standard test, but a very common mistake is to plot too few random points, so you get a false impression of an uneven distribution.
You need to plot > 100K random points to get an impression of the true distribution, for something like the 8,192 unique locations in your test.
True randomness does not produce even distribution, rather it creates bunches.
You are mistaken, and fooled by a subset of points.
random() produces a uniform distribution over the interval. To see that this is true, run this little program, which produces a histogram of 10000 points randomly distributed over the interval (0-199), inclusive.
//random number distribution histogram, Arduino Uno
int hist[200];
int n=10000;
void setup() {
Serial.begin(115200);
while(!Serial);
for (int i=0; i<n; i++) hist[random(200)]++;
for (int i=0; i<200; i++) {
Serial.print(i);
Serial.print(", ");
Serial.println(hist[i]);
}
}
void loop() {
}
As you increase n, the minor (and statistically expected) variations between neighboring intervals become less significant.
Probably...
But... I recognize the uniform distribution of randomness tends toward a Bell curve. Perhaps that is due to physical intervention, which will always be present, like the distribution of galaxies in the universe, or water molecules in a jet exhaust... just today on a cold afternoon I looked up to see quite a few jet trails and saw each had a pattern like bunch of cotton balls on an endless stick. After random as the combustion, condensation and air currents caused by the passing jet, there remained a pattern.
I have let my little OLED test run for long enough to "whiten" most of the screen... but that is only 1,024 possible locations, even when over-drawn. Since I am only using Arduino to test Arduino randomness, I think the scope should be nothing outside available tools (Arduino code and equipment).
Thank you for the code example. I look forward to it showing me things.
No. That is called the Gaussian distribution.
You can estimate the Gaussian distribution using the uniform distribution, which is one of the reasons why random() was written to produce the uniform distribution. In fact you can estimate any other useful distribution (such as Poisson) using random().
When throwing a fair die a large number of times, you expect each of the six sides to come up equally often in the long run. Right?
Tossing a fair die 10,000 times with random(), using the program posted above.
Each face or bin is expected to show up on average 1667 times, plus or minus the statistically expected counting error of sqrt(1667) = 40.
In other words, 1667 +/- 40:
1, 1640
2, 1694
3, 1676
4, 1706
5, 1604
6, 1680
Thank you. I have two normally open buttons connected from pin to ground. They are on a chess clock and are randomly closed the a player makes a move. Can this setup be used to generate the seed? The random selection can only be made by the hardware when time runs out.
I do not. Because to me the dice are physical, and even if "fair", I expect the house to win with "just" 7 and 11 (5/2, 2/5, 4/3, 3/4, 6/5, 5/6) and I get the remaining combinations. I am sure there is math behind the house. That is why I do not gamble. I rather get the free drinks and pay for my friend to loose my money.
Got it. Sorry for using the wrong terms.
I'm looking forward to the results your sketch. I've started a 1000 x 1000 x 1000 pixel drawing that should take a looong time.
Ahh, you expect all dice to be loaded. Well, "good luck", as they say!
Gaussian.
I have a button connected from GND to PIN set as INPUT_PULLUP that randomly start and stop a clock. The pin will be High or Low. Is it possible to get a random number from that setup?
History has clearly demonstrated the answer depends entirely on the implementation. If you want an answer, post your code.
Or, just use the code referenced in post #10.
When in setup(), I could see your sketch count to "199,58" and then stop.... I could not get it to work (it gave me a memory error in the simulator).
The three randomize functions I simulated show even distribution, to your point.
The dots showing clumps, but are overwritten and show distribution.
The bar graph has spikes, but moves across the screen evenly.
The centered dot, stays around the middle.
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
int w = 128, h = 64; // OLED width and height
int a, b, x, y, z, c[64]; // for bars
int rollover = 100; // for dots
int hist[200]; // jremington
int n = 10000; // jremington
void setup() {
Serial.begin(9600);
// jrem(); // must be in setup(), and comment-out the OLED lines in setup()
randomSeed(analogRead(A0));
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;); // Don't proceed, loop forever
}
display.clearDisplay();
display.display();
}
void loop() {
// jrem(); // if in loop(), first value is 0 to 199, second value keeps increasing
// dots(); // fill the screen with dots
// bars(); // bar graph
center(); // move dot left and right
}
void jrem() { // jremington
//random number distribution histogram, Arduino Uno
// int hist[200];
// int n = 10000;
while (!Serial);
for (int i = 0; i < n; i++) hist[random(200)]++;
for (int i = 0; i < 200; i++) {
Serial.print(i);
Serial.print(", ");
Serial.println(hist[i]);
}
}
void center() {
// start center, add -1, 0, 1 (move left, no move, move right)
display.drawLine(w / 2, h / 2 + 1, w / 2, h, WHITE); // reference line
display.display();
x = w / 2; // middle of OLED
y = random(-1, 2); // -1, 0, 1
x += y; // left, none, right
display.drawPixel(z, 31, BLACK); // erase old pixel
display.drawPixel(x, 31, WHITE); // draw new pixel
display.display();
z = x; // new pixel becomes old pixel
}
void bars() { // rotating axes 90 degrees causes spurious verticle pixels near mid screen
b = random(h); // column
c[b]++; // accumulate columns
a = c[b]; // for cleaner drawPixel()
display.drawPixel(a, b, WHITE);
display.display();
}
void dots() {
display.drawPixel(random(128), random(64), WHITE);
display.display();
x++;
if (x == rollover) { // 100 = 10^2
x = 0;
// Serial.print("x");
y++;
if (y == rollover) { // 100 * 100 = 10^4
y = 0;
Serial.println(rollover * rollover);
z++;
if (z == rollover) { // 100 * 100 * 100 = 10^6
z = 0;
Serial.println(rollover * rollover * rollover);
}
}
}
}
what kind of sensors are connected to each pin? Any chance to get some varying value at startup?
Do you have a user button? When will it pressed the first time after startup?
As have been pointed out, millis() requires some human action before millis() is used, human action which causes a human delay. That will work.
If no human action is involved, except turning the device on, we still need to separate two cases. Is the device on 24/7? Or is the device turned off and on again and each time it is turned on it needs to output random things? If it's on 24/7, just hardcode one random seed. After that you rely on your random number generator. It might repeat itself after 32768 iterations or after one zillion iterations, depending on what generator you have.
But if the device is turned off and on again, have it write (millis() + original_seed) to EEPROM memory every once in a while, while the program is running. And when the device is turned off, the last written value stays in EEPROM. At next start, the EEPROM value is read and used as seed, and as well set as original_seed. In short, the running time from turn on to turn off is used as the cumulated seed for next turn on.