diff --git a/examples/binomial.cpp b/examples/binomial.cpp new file mode 100644 index 000000000..b25bb8c67 --- /dev/null +++ b/examples/binomial.cpp @@ -0,0 +1,67 @@ +/* Plots the distribution histogram of the fast_binomial algorithm + * (spoiler alert: it's pleasingly (1/2)^N all the way :D) + */ +#include +#include +#include +#include +#include + +#include +#include + +#include "utils/random/fast_binomial.hpp" + +static constexpr unsigned B = 24; +static thread_local FastBinomial rnd; + +static constexpr unsigned M = 4; +static constexpr size_t N = 1ULL << 34; +static constexpr size_t per_thread_iters = N / M; + +std::array, B> buckets; + +void generate() +{ + for(size_t i = 0; i < per_thread_iters; ++i) + buckets[rnd() - 1].fetch_add(1); +} + +int main(void) +{ + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + + auto bar_len = w.ws_col - 20; + + std::array threads; + + for(auto& bucket : buckets) + bucket.store(0); + + for(auto& t : threads) + t = std::thread([]() { generate(); }); + + for(auto& t : threads) + t.join(); + + auto max = std::accumulate(buckets.begin(), buckets.end(), (uint64_t)0, + [](auto& acc, auto& x) { return std::max(acc, x.load()); }); + + std::cout << std::fixed; + + for(size_t i = 0; i < buckets.size(); ++i) + { + auto x = buckets[i].load(); + auto rel = bar_len * x / max; + + std::cout << std::setw(2) << i + 1 << " "; + + for(size_t i = 0; i < rel; ++i) + std::cout << "="; + + std::cout << " " << 100 * (double)x / N << "%" << std::endl; + } + + return 0; +} diff --git a/examples/xorshift.cpp b/examples/xorshift.cpp new file mode 100644 index 000000000..e52ab471e --- /dev/null +++ b/examples/xorshift.cpp @@ -0,0 +1,65 @@ +/* Plots the distribution histogram of the xorshift algorithm + * (spoiler alert: it's pleasingly uniform all the way :D) + */ +#include +#include +#include +#include + +#include +#include + +#include "utils/random/xorshift128plus.hpp" + +static thread_local Xorshift128plus rnd; +static constexpr unsigned B = 1 << 10; +static constexpr uint64_t K = (uint64_t)(-1) / B; + +static constexpr unsigned M = 4; +static constexpr size_t N = 1ULL << 34; +static constexpr size_t per_thread_iters = N / M; + +std::array, B> buckets; + +void generate() +{ + for(size_t i = 0; i < per_thread_iters; ++i) + buckets[rnd() / K].fetch_add(1); +} + +int main(void) +{ + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + + auto bar_len = w.ws_col - 20; + + std::array threads; + + for(auto& bucket : buckets) + bucket.store(0); + + for(auto& t : threads) + t = std::thread([]() { generate(); }); + + for(auto& t : threads) + t.join(); + + auto max = std::accumulate(buckets.begin(), buckets.end(), 0u, + [](auto& acc, auto& x) { return std::max(acc, x.load()); }); + + std::cout << std::fixed; + + for(auto& bucket : buckets) + { + auto x = bucket.load(); + auto rel = bar_len * x / max; + + for(size_t i = 0; i < rel; ++i) + std::cout << "="; + + std::cout << " " << 100.0 * x / N * B - 100 << "%" << std::endl; + } + + return 0; +} diff --git a/utils/random/fast_binomial.hpp b/utils/random/fast_binomial.hpp index 782f00c2a..df08128f0 100644 --- a/utils/random/fast_binomial.hpp +++ b/utils/random/fast_binomial.hpp @@ -27,11 +27,9 @@ class FastBinomial // ------------------ // 16 1111 -> 5 ===== - static constexpr uint64_t mask = (1 << N) - 1; + static constexpr uint64_t mask = (1ULL << N) - 1; public: - FastBinomial() = default; - unsigned operator()() { while(true) @@ -44,7 +42,9 @@ public: auto x = random() & mask; // if we have all zeros, then we have an invalid case and we - // need to generate again + // need to generate again, we have this every (1/2)^N times + // so therefore we could say it's very unlikely to happen for + // large N. e.g. N = 32; p = 2.328 * 10^-10 if(UNLIKELY(!x)) continue; diff --git a/utils/random/xorshift128plus.hpp b/utils/random/xorshift128plus.hpp index 1602ffda4..f98c558bc 100644 --- a/utils/random/xorshift128plus.hpp +++ b/utils/random/xorshift128plus.hpp @@ -1,5 +1,4 @@ -#ifndef MEMGRAPH_UTILS_RANDOM_XORSHIFT_HPP -#define MEMGRAPH_UTILS_RANDOM_XORSHIFT_HPP +#pragma once #include #include @@ -25,7 +24,6 @@ public: // the number generated by MT can be full of zeros and xorshift // doesn't like this so we use MurmurHash3 64bit finalizer to // make it less biased - s[0] = avalance(dist(gen)); s[1] = avalance(dist(gen)); } @@ -56,5 +54,3 @@ private: return s; } }; - -#endif