diff --git a/README.md b/README.md index 0a0a978..4f2e754 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ and modules which are documented and supported. 4.5 [Timed function](./README.md#45-timed-function) Time execution with a decorator. 4.6 [ESP8266 MQTT benchmark](./README.md#46-esp8266-mqtt-benchmark) Test performance of MQTT with official library. 4.7 [Rotary incremental encoder](./README.md#47-rotary-incremental-encoder) Fast, simple, proven algorithm. - 4.8 [A pseudo random number generator](./README.md#48-a-pseudo-random-number-generator) + 4.8 [Pseudo random number generators](./README.md#48-pseudo-random-number-generators) 4.9 [Verifying incrementing sequences](./README.md#49-verifying-incrementing-sequences) Test communications drivers. 4.10 [Bitmaps](./README.md#410-bitmaps) Non-allocating ways to access bitmaps. 4.11 [Functors and singletons](./README.md#411-functors-and-singletons) Useful decorators. @@ -213,7 +213,7 @@ The [encoder_portable.py](./encoders/encoder_portable.py) version should work on all MicroPython platforms. Tested on ESP8266. Note that interrupt latency on the ESP8266 limits performance. ESP32 has similar limitations. -## 4.8 A pseudo random number generator +## 4.8 Pseudo random number generators On the Pyboard V1.1, true random numbers may be generated rapidly with `pyb.rng()` which uses a hardware random number generator on the @@ -226,7 +226,12 @@ number generator is seeded with an arbitrary initial value. On each call to the function it will return a random number, but (given the same seed) the sequence of numbers following initialisation will always be the same. -See [random.py](./random/random.py) for usage and timing documentation. +See [random.py](./random/random.py) for usage and timing documentation. The +[yasmarang generator](./random/yasmarang.py) is also included, along with my +own [cheap random](./random/cheap_rand.py). The latter constrains calculations +to 30 bits, allowing its use in an ISR. It comes with no guarantees of random +quality and the only statistical test is that the mean converges on the right +value. ## 4.9 Verifying incrementing sequences diff --git a/random/cheap_rand.py b/random/cheap_rand.py new file mode 100644 index 0000000..ce8651f --- /dev/null +++ b/random/cheap_rand.py @@ -0,0 +1,37 @@ +# pseudorandom numbers for MicroPython. ISR friendly version. +# Probably poor quality numbers but useful in test scripts + +# Author: Peter Hinch +# Copyright Peter Hinch 2020 Released under the MIT license + +# Example usage to produce numbers between 0 and 99 +# rand = cheap_rand(100) +# successive calls to rand() will produce the required result. + +def cheap_rand(modulo, seed=0x3fba2): + x = seed + def func(): + nonlocal x + x ^= (x & 0x1ffff) << 13; + x ^= x >> 17; + x ^= (x & 0x1ffffff) << 5; + return x % modulo + return func + +# The sum total of my statistical testing +#import pyb, micropython, time +#rand = cheap_rand(1000) +#sum = 0 +#cnt = 0 +#def avg(n): + #global sum, cnt + #sum += n + #cnt += 1 +#def cb(t): + #n = rand() + #micropython.schedule(avg, n) + +#t = pyb.Timer(1, freq=20, callback=cb) +#while True: + #time.sleep(1) + #print(sum/cnt) diff --git a/random/yasmarang.py b/random/yasmarang.py new file mode 100644 index 0000000..36b60a7 --- /dev/null +++ b/random/yasmarang.py @@ -0,0 +1,25 @@ +# yasmarang pseudorandom number generator. +# Source http://www.literatecode.com/yasmarang + +# Author: Peter Hinch +# Copyright Peter Hinch 2020 Released under the MIT license + +def yasmarang(): + pad = 0xeda4baba + n = 69 + d = 233 + dat = 0 + def func(): + nonlocal pad, n, d, dat + pad = (pad + dat + d * n) & 0xffffffff + pad = ((pad<<3) + (pad>>29)) & 0xffffffff + n = pad | 2 + d = (d ^ ((pad<<31) + (pad>>1))) & 0xffffffff + dat ^= ((pad & 0xff) ^ (d>>8) ^ 1) & 0xff + return (pad^(d<<5)^(pad>>18)^(dat<<1)) & 0xffffffff + return func + +# Test: produces same outcome as website. +#ym = yasmarang() +#for _ in range(20): + #print(hex(ym()))