]> git.localhorst.tv Git - tacos.git/blobdiff - src/rand/GaloisLFSR.hpp
basic floor idea
[tacos.git] / src / rand / GaloisLFSR.hpp
diff --git a/src/rand/GaloisLFSR.hpp b/src/rand/GaloisLFSR.hpp
new file mode 100644 (file)
index 0000000..94b12d0
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef TACOS_RAND_GALOISLFSR_HPP_
+#define TACOS_RAND_GALOISLFSR_HPP_
+
+#include <cstdint>
+#include <limits>
+
+
+namespace tacos {
+
+class GaloisLFSR {
+
+public:
+       // seed should be non-zero
+       explicit GaloisLFSR(std::uint64_t seed) noexcept
+       : state(seed) {
+               if (state == 0) {
+                       state = 1;
+               }
+       }
+
+       // get the next bit
+       bool operator ()() noexcept {
+               bool result = state & 1;
+               state >>= 1;
+               if (result) {
+                       state |= 0x8000000000000000;
+                       state ^= mask;
+               } else {
+                       state &= 0x7FFFFFFFFFFFFFFF;
+               }
+               return result;
+       }
+
+       template<class T>
+       T operator ()(T &out) noexcept {
+               constexpr int num_bits =
+                       std::numeric_limits<T>::digits +
+                       std::numeric_limits<T>::is_signed;
+               for (int i = 0; i < num_bits; ++i) {
+                       operator ()();
+               }
+               return out = static_cast<T>(state);
+       }
+
+       template<class T>
+       T Next() noexcept {
+               T next;
+               return (*this)(next);
+       }
+
+       float SNorm() noexcept {
+               return float(Next<std::uint32_t>()) * (1.0f / 2147483647.5f) - 1.0f;
+       }
+
+       float UNorm() noexcept {
+               return float(Next<std::uint32_t>()) * (1.0f / 4294967295.0f);
+       }
+
+       template<class Container>
+       typename Container::reference From(Container &c) {
+               return c[Next<typename Container::size_type>() % c.size()];
+       }
+       template<class Container>
+       typename Container::const_reference From(const Container &c) {
+               return c[Next<typename Container::size_type>() % c.size()];
+       }
+
+private:
+       std::uint64_t state;
+       // bits 64, 63, 61, and 60 set to 1 (counting from 1 lo to hi)
+       static constexpr std::uint64_t mask = 0xD800000000000000;
+
+};
+
+}
+
+#endif