Skip to content

Commit

Permalink
Add 16 and 32 bit feeds.
Browse files Browse the repository at this point in the history
  • Loading branch information
q-uint committed Sep 1, 2021
1 parent 789a34f commit 9c1b60e
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 8 deletions.
23 changes: 21 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,28 @@

## LFSR (linear feedback shift register)

Generates up to `1-2^n` unique numbers.
### Types of LFSR

- LFSR8: 8-bit LFSR with a period of 255.
#### 8-bit

```text
X^8 + X^6 + X^5 + X^4 + 1
-> 2^8 -1 = 255
```

#### 16-bit

```text
X^16 + X^14 + X^13 + X^11 + 1
-> 2^16 - 1 = 65_535
```

#### 32-bit

```text
X^32+ X^22 + X^2 + X^1 + 1
-> 2^32 - 1
```

### Usage

Expand Down
62 changes: 58 additions & 4 deletions src/LFSR.mo
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import Array "mo:base/Array";
import Int "mo:base/Int";
import Iter "mo:base/Iter";
import Nat8 "mo:base/Nat8";
import Nat16 "mo:base/Nat16";
import Nat32 "mo:base/Nat32";
import Nat64 "mo:base/Nat64";
import Time "mo:base/Time";

Expand All @@ -12,10 +14,9 @@ module {
next() : (T, Bool);
};

// An 8 bit linear feedback shift register.
// An 8-bit linear feedback shift register.
public class LFSR8(
// Seed.
s : ?Nat8,
s : ?Nat8, // Seed.
) {
private let seed : Nat8 = switch (s) {
case (null) { nat8(Int.abs(Time.now())); };
Expand All @@ -28,12 +29,57 @@ module {
Bool, // Whether the sequence was completed and is restarting.
) {
let s = state;
let b = (s >> 0) ^ (s >> 2) ^ (s >> 3) ^ (s >> 4);
// X^8 + X^6 + X^5 + X^4 + 1
let b = (s >> 0) ^ (s >> 2) ^ (s >> 3) ^ (s >> 4) & 1;
state := (s >> 1) | (b << 7);
(state, state == seed);
};
};

// An 16-bit linear feedback shift register.
public class LFSR16(
s : ?Nat16, // Seed.
) {
private let seed : Nat16 = switch (s) {
case (null) { nat16(Int.abs(Time.now())); };
case (? s) { s; };
};
private var state = seed;

public func next() : (
Nat16, // Next pseudo random number.
Bool, // Whether the sequence was completed and is restarting.
) {
let s = state;
// X^16 + X^14 + X^13 + X^11 + 1
let b = (s >> 0) ^ (s >> 2) ^ (s >> 3) ^ (s >> 5) & 1;
state := (s >> 1) | (b << 15);
(state, state == seed);
};
};

// An 32-bit linear feedback shift register.
public class LFSR32(
s : ?Nat32, // Seed.
) {
private let seed : Nat32 = switch (s) {
case (null) { nat32(Int.abs(Time.now())); };
case (? s) { s; };
};
private var state = seed;

public func next() : (
Nat32, // Next pseudo random number.
Bool, // Whether the sequence was completed and is restarting.
) {
let s = state;
// X^32+ X^22 + X^2 + X^1 + 1
let b = (s >> 0) ^ (s >> 10) ^ (s >> 30) ^ (s >> 31) & 1;
state := (s >> 1) | (b << 31);
(state, state == seed);
};
};

public func toIter<T>(feed : LFSR<T>) : Iter.Iter<T> = object {
let lfsr = feed;
var restarted = false;
Expand Down Expand Up @@ -63,4 +109,12 @@ module {
private func nat8(n : Nat) : Nat8 {
Nat8.fromNat(Nat64.toNat(Nat64.fromNat(n) & 0xFF));
};

private func nat16(n : Nat) : Nat16 {
Nat16.fromNat(Nat64.toNat(Nat64.fromNat(n) & 0xFFFF));
};

private func nat32(n : Nat) : Nat32 {
Nat32.fromNat(Nat64.toNat(Nat64.fromNat(n) & 0xFFFFFFFF));
};
};
16 changes: 14 additions & 2 deletions test/LFSR.mo
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
import Hash "mo:base/Hash";
import Iter "mo:base/Iter";
import Nat "mo:base/Nat";
import Nat8 "mo:base/Nat8";
import Nat16 "mo:base/Nat16";
import TrieSet "mo:base/TrieSet";

import IO "mo:io/IO";

import D "mo:base/Debug";

import LFSR "../src/LFSR";

do {
let feed = LFSR.LFSR8(null);

var s = TrieSet.empty<Nat>();
var i = 0;
var restarted = false;
while (not restarted) {
i += 1;
let (_, r) = feed.next();
let (v, r) = feed.next();
let n = Nat8.toNat(v);
if (TrieSet.mem<Nat>(s, n, Hash.hash(n), Nat.equal)) {
assert(false);
};
s := TrieSet.put(s, n, Hash.hash(n), Nat.equal);
restarted := r;
};
if (i != 0xFF) assert(false);
Expand Down

0 comments on commit 9c1b60e

Please sign in to comment.