Last active
February 7, 2019 00:50
-
-
Save Sam-Belliveau/e14c364f7b07b7ec63d0d3a1c357501b to your computer and use it in GitHub Desktop.
a replacement for std::random_device that lets you change the result type, and uses a buffer.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #ifndef SAMS_RANDOM_DEVICE_HPP | |
| #define SAMS_RANDOM_DEVICE_HPP | |
| #include <cstddef> // std::size_t | |
| #include <fstream> // std::ifstream | |
| #include <ostream> // std::ostream | |
| #include <limits> // min and max | |
| #include <cmath> // std::log2 - entropy | |
| template<class RT = unsigned, std::size_t BufferSize = 0x100 / sizeof(RT)> | |
| class RandomDevice | |
| { | |
| public: | |
| // types | |
| typedef RT result_type; | |
| // generator characteristics | |
| static inline constexpr result_type min() { return std::numeric_limits<RT>::min(); } | |
| static inline constexpr result_type max() { return std::numeric_limits<RT>::max(); } | |
| // constructors | |
| RandomDevice(const char* __token = "/dev/urandom") | |
| { | |
| _random_data = std::ifstream(__token, std::ios::in | std::ios::binary); | |
| _buffer = new result_type[BufferSize]; | |
| updateBuffer(); | |
| } | |
| ~RandomDevice() | |
| { | |
| _random_data.close(); | |
| delete[] _buffer; | |
| } | |
| // generating functions | |
| result_type operator() () | |
| { | |
| if(_index >= BufferSize) { updateBuffer(); } | |
| return _buffer[_index++]; | |
| } | |
| friend std::ostream& operator<<(std::ostream& out, const RandomDevice& rng) | |
| { | |
| out << rng(); | |
| return out; | |
| } | |
| // entropy | |
| double entropy() const noexcept | |
| { | |
| std::size_t byte_count[0x100] = {}; | |
| const std::uint8_t* raw_array = reinterpret_cast<const std::uint8_t*>(_buffer); | |
| const std::size_t raw_size = BufferSize * sizeof(result_type); | |
| for(std::size_t i = 0; i < raw_size; ++i) | |
| ++byte_count[raw_array[i]]; | |
| double entropy = 0; | |
| for(double count : byte_count) | |
| { | |
| if(count != 0) | |
| { | |
| const double p = double(count) / double(raw_size); | |
| entropy -= p * std::log2(p) / 8.0; | |
| } | |
| } | |
| return entropy; | |
| } | |
| private: | |
| // no copy functions | |
| RandomDevice(const RandomDevice&); // = delete; | |
| RandomDevice& operator=(const RandomDevice&); // = delete; | |
| // random device file | |
| std::ifstream _random_data; | |
| // random buffer | |
| std::size_t _index; | |
| result_type* _buffer; | |
| void updateBuffer() | |
| { | |
| _index = 0; | |
| _random_data.read(reinterpret_cast<char*>(_buffer), BufferSize * sizeof(result_type)); | |
| } | |
| }; | |
| #endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment