Show HN: Fast Random Library for C++17

2025-06-0211:095258github.com

Collection of self-contained header-only libraries for C++17 - DmitriBogdanov/UTL

You can’t perform that action at this time.


Read the original article

Comments

  • By OskarS 2025-06-0215:331 reply

    I think it looks great! Might be using this in a future project.

    One note on API design: I think it's a FANTASTIC idea to have default `rand()` functions available, since very often, you don't really care about the generator and you're just like "just give me a random number, i don't care how". But if you do, you shouldn't have a `seed()` function, because that means you can then never upgrade it without breaking your API contract. It should always be seeded with entropy. This is why glibc's `rand()` is still using an LCG from the late neolithic, they can't ever update it without breaking a gazillion applications and tests. This is the classic example of "Hyrum's law". Doing this also helps with thread-safety: you can just make the seed/state thread-local and then it just works.

    Basically, if you want the ability to seed your PRNG, you also need to specify the generator explicitly. The global one is for convenience only, and there should be no ability in the API to seed it.

    EDIT: btw, this is a really nice thing about C++, doing this is dead easy:

        int rand() {
            thread_local generator my_generator { seed_with_entropy() };
            return my_generator.rand();
        }

    • By quietbritishjim 2025-06-0216:173 reply

      I forget the details off hand, but I thought that C++ notoriously fails to include much entropy in the generator unless you go through some complex multiline dance that forces the seed sequence to actually include it.

      • By SiempreViernes 2025-06-0216:54

        I think Oskars point is that if you say "I just want a random number, I don't care how" you can't very well be upset the seed is bad as that would be caring.

      • By kccqzy 2025-06-0217:441 reply

        You mean creating the generator with a deterministic seed is shorter code than creating it with entropy? Well yes, because the entropy source is std::random_device so it's an extra line for an extra variable.

        Don't think it's a problem in practice because every online tutorial or Stack Overflow posts contain that multi-line snippet for real entropy. C++ programmers are somewhat used to verbosity anyways.

        • By quietbritishjim 2025-06-039:10

          > You mean creating the generator with a deterministic seed is shorter code than creating it with entropy?

          No, it was more like: it's easy to write code that appears to fully seed a RNG with entropy, but in fact only seeds a tiny part of its state. Making it seed the whole lot, especially in a portable way, is surprisingly hard to get right. But I now can't find the article that explains this.

          I seem to remember I had to use Boost.Random instead of the C++ standard library to do this in a real program, but this was a few years ago and the latest standard that was available in most implementations was C++11. Perhaps things have improved since.

      • By OskarS 2025-06-0216:58

        I’m assuming here that ”generator” has a decent enough constructor that seeds it properly. If it doesn’t, and you have to cycle it a few times to ”warm it up”, it’s not much more complicated, just factor out the initialization code into a function or lambda and use that to initialize the thread_local.

  • By jll29 2025-06-0218:19

    Thanks for sharing, this is a very well-written and useful set of libraries, not just random, but also the other sub-libraries of utl.

    One caveat:

    > Note 2: If no hardware randomness is available, std::random_device falls back onto an internal PRNG ....

    > ...

    > std::random_device has a critical deficiency in it's design — in case its implementation doesn't provide a proper source of entropy, it is free to fallback onto a regular PRNGs that don't change from run to run. The method std::random_device::entropy() which should be able to detect that information is notoriously unreliable and returns different things on every platform.

    > entropy() samples several sources of entropy (including the std::random_device itself) and is (almost) guaranteed to change from run to run even if it can't provide a proper hardware-sourced entropy that would be suitable for cryptography.

    Personally, I think it would be best if there was a way to communicate to the system (or here, to the library in specific) what is the use case. For cryptographic applications, I don't want the library to fall back gracefully to something insecure; I would want a dark red critical error message and immediate termination with an "insufficient entropy error" error code.

    However, for a game graceful degradation might be quite okay, because nobody is going to die in the real world if a monster behaves a little less random.

    I learned a lot about recent advances in pseudo-random number generators by reading your code and associated documentation, including some stuff that DEK has yet to incorporate into volume 2 of TAOCP. ;)

  • By spacechild1 2025-06-0215:441 reply

    This looks nice! One thing I find particularly noteworthy:

    - Faster uniform / normal distributions that produce same sequences on every platform

    This is very useful if you want to reliably repeat simulations across platforms!

    One question:

        template<class T>
        constexpr T& rand_choice(std::initializer_list<T> objects) noexcept;
    
    
    Isn't this returning a reference to a local variable? In my understanding, 'objects' is destroyed when rand_choice() returns.

    • By GeorgeHaldane 2025-06-0216:35

      Thanks, that is indeed the case when list doesn't consist of literals, fixed in the new commit.

HackerNews