Recently I was writing a program and needed a large set of random numbers to use as inputs. It was quite simple to do using C#, and in only a few lines of code I possessed seemingly endless amounts of random numbers at my fingertips. Typically I would think “Huh. Neat.” and go about my day, but for some reason that morning I found the whole concept oddly intriguing. I mean, where were these numbers even coming from? Aren’t processors specifically designed to follow given instructions? If so, how are they able to generate randomness?
You may be disappointed to hear that there is no black magic involved.
You may be even more disappointed to hear that in most cases these numbers aren’t actually random.
To elaborate on the latter, I’ll show an example. Below is code of how one would receive a sequence of “random” numbers using C#.
It’s quite simple code, but there are some interesting happenings behind the scenes. Initially, the Random object (we’ll call it rand) is initialized with the default constructor. Behind the scenes rand is assigned a seed value based on the current value of the system clock. For example, let’s assume the current time is 3745 microseconds past 9:41 PM. Rand would then have a seed value of 3745. This seed is then used to retrieve a sequence of pre-determined numbers that are then given back to the user.
This concept of seeding is the main idea that drives many random number generators: a seed is chosen at random using some observable physical process (C# uses elapsed microseconds on the system clock), then a sequence of pre-determined numbers retrieved using this seed. Number generators that follow this paradigm are called pseudorandom number generators.
While my questions were answered for the most part, I became curious about how one could make a true random number generator. No pseudo-randomness, no pre-defined sequences. I wanted to know if there was a way to generate truly random numbers. After some brainstorming and research, I came upon the idea of using atmospheric noise.
Atmospheric noise is defined by Wikipedia as “radio noise caused by natural atmospheric processes, primarily lightning discharges in thunderstorms.” My idea was to take advantage of this randomness of this phenomenon and use it to generate extremely high quality random numbers. I figured if I could capture this process using an audio recorder, I could then use the randomness of the bits in the audio file as a foundation for generating random numbers.
It turns out it’s quite simple to record atmospheric noise. All one needs is a radio (or something with an antenna) and an audio recorder. The radio then needs to be set to a station where only static can be heard. This static, also known as radio noise, is really just the antenna receiving unwanted radio signals such as lightning, random thermal noise in the receiver’s circuitry, and man-made electrical radio interference.
I decided to use the microphone on my iPhone to record static coming from a radio station on my car radio for one minute. Then, I converted this audio file from M4A (iPhone’s default audio recording file format) to uncompressed WAV format using an online audio converter. The reason for this is because uncompressed WAV will allow me to easily grab and manipulate the raw data of the audio. Next, I had to figure out how to extract the bits of the WAV file to generate the numbers. I needed to do a bit of research for this part, and eventually found this helpful chart that details the structure of a WAV file.
To put it simply, the first 44 bytes of a WAV file is the header, which is just information about the file itself. I needed to skip past the first 44 bytes of the file to extract the raw data itself.
Now, the fun part begins: working with the raw data. The important thing to understand is that the raw data in a WAV file is effectively a bunch of 16-bit long sequences placed back-to-back, each one being called a “sample.” A sample is a y-value measurement of a sound wave at a given time. Below is an example of what a sound wave could look like.
The y-value of one blue dot in the above picture would represent the value of one 16-bit sample.
Now comes some neat bit manipulation. I believe it’s best to explain this visually, so I made a table. The table below represents 10 back-to-back samples in the raw data of a WAV file. Please note that I greatly exaggerated these values to make the concept more obvious.
If you look closely, you’ll notice that the first bit fluctuates wildly while the other bits tend to stay the same. This is because in WAV file format, the 16-bit samples are arranged in little endian order, meaning the bits in a sample are arranged from least significant to most significant. So by taking only the least significant bit of the samples, we can generate extremely high quality random numbers because they tend to fluctuate wildly due to their high precision.
Using this concept, I devised the following bit-sampling algorithm for a WAV file.
- Extract all bytes from the WAV file after the 44th byte (we only want raw data)
- Convert these bytes to bits
- Extract and store the first bit (least significant) of every 16-bit sample
Now that we have the random bits, random number generation is quite simple. Below is the algorithm I wrote that generates a random number within a range using our stored random bits.
- Take the range of the max and the min.
- Take the floor of log base 2 of the range. This is the smallest number of bits we need to extract to satisfy our range constraint. We’ll call this X.
- Extract X number of bits from your pool of random bits.
- Convert these X bits from binary to decimal. If the result is greater than the range, go back to step 3.
- Add the number generated from step 4 to the min. This is the random number in your desired range.
Now for the grand conclusion: the results.
From my 1 minute audio recording of car radio static, totaling 5.56 megabytes in size, I was able to generate 501203 random numbers between 0 and 10.
The average and the distribution of numbers make it clear that this approach is valid, and that I successfully created a high quality random number generator.
I found this project to be quite rewarding because it was an idea that just randomly popped into my head one day, and I was able to create an interesting learning experience out of it. It allowed me to think outside the box and really appreciate that there are no boundaries when it comes to coding and thinking creatively.