-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace rnd macros with STL alternatives #225
base: master
Are you sure you want to change the base?
Conversation
I don't think we should include c++ standard library headers in common header files like tools.h because it makes the build time slow. I don't even think this is needed in this pull request because |
We could introduce a Re. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot! Looks pretty good to me: you've made the right assumptions about the old code, and replaced them correctly with STL stuff.
I left some feedback below.
src/shared/tools.cpp
Outdated
#define N (624) | ||
#define M (397) | ||
#define K (0x9908B0DFU) | ||
std::random_device rndseed; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should provide a short comment why we store our seed statically. Of course it makes sense to do so (otherwise you could just use the random device directly, which is, in itself, a form of RNG). Future readers however might not be into PRNGs as much.
src/shared/tools.cpp
Outdated
|
||
static uint state[N]; | ||
static int next = N; | ||
int rnd(int value) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would appreciate a more descriptive method name, and perhaps a docstring.
@@ -81,9 +82,6 @@ static inline int bitscan(uint mask) | |||
#endif | |||
#endif | |||
|
|||
#define rnd(x) ((int)(randomMT()&0x7FFFFFFF)%(x)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a good idea to replace these macros.
extern int rnd(int); | ||
extern float rndfloat(int); | ||
extern int detrnd(int, int); | ||
extern uint tmprnd(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume the following mapping now, given their previous use:
rnd
->rnd
rndscale
->rndfloat
detrnd
->detrnd
randomMT
->tmprnd
In order to allow people who are used to the old code understand the new format, I think it makes sense to add docstrings to the new functions, explaining what the new ones do.
src/shared/tools.h
Outdated
@@ -4,6 +4,7 @@ | |||
#define _TOOLS_H | |||
#include <utility> | |||
#include <vector> | |||
#include <random> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably not do this. @robalni has had a very good point, which is STL headers likely slowing down compilation. I think a random.h
is more appropriate for these new declarations.
Regarding ranlux48 vs. MT19937, I've come to another conclusion than you, performance wise. I've put together some (very shady but good enough) "benchmark". #include <random>
int main() {
std::random_device rndseed;
//std::ranlux48 rndalg(rndseed());
std::mt19937 rndalg(rndseed());
for (uint64_t i = 0; i < (1ULL << 24); ++i) {
rndalg();
}
} With We should discuss what we want. In games, I think "no predictability" (which is actually just a security property) isn't necessarily the goal. Performance, however, is. We should not use any of these PRNGs for serious work, as they're just not good at it (boost-random is significantly different, but also a lot better than what you get in the STL). We just need a reasonably well-distributed random number generation. MT19937 will provide that, but, looking at some Internet suggestions, it might even be overkill (many games just use xor shift algorithms for tasks like randomizing spawns or weapons). Given that we've been using MT so far, I think we should just continue to do so. I am eager to see how that (shady) benchmark performs on @voidanix's computer. I can't reproduce that ranlux should run faster than MT. |
src/shared/tools.cpp
Outdated
y ^= (y << 15) & 0xEFC60000U; | ||
y ^= (y >> 18); | ||
return y; | ||
std::ranlux48 algseed(seed); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand detrnd
is supposed to mean "deterministic random number", but I'm not sure what properties the implementation is supposed to provide. We might want to check its uses. The only reason I could come up with where you'd want to specify your own seed is to get the same results on more than one host. But that seems like a bad idea.
Regarding the reproducibility of the results of std::uniform_int_distribution
, it is not stable over different implementations. While it will always return the same sequence of numbers in, e.g., libstdc++, libc++ differs.
Here's an example:
#include <iostream>
#include <random>
int main() {
// https://xkcd.com/221/
std::mt19937 rnd(4);
std::uniform_int_distribution<> dist(0, (1ULL << 16));
std::cout << dist(rnd) << std::endl;
}
With GCC 7.5.0 with libstdc++, it prints 63376. With Clang 9 and libc++, it gives you 11863. So, the deterministic property of this little function is only provided if you can guarantee the same STL implementation is used. Hence, depending on the purpose of this function, the entire concept should be reviewed in the context of Blue Nebula.
Might be worth creating a new issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
afaik detrnd
provides more "consistent" and thus "closer" results than rnd
, which for example results useful for picking a certain range of colors for exploding mines (which tend to turn red when using rnd
) or the flashes on the player which holds the rocket (it's way too fast with rnd
), so it's not about getting the same results.
std::uniform_int_distribution
is a non-issue as the results don't need to be reproducible between different STL implementations
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
afaik detrnd provides more "consistent" and thus "closer" results than rnd
Well, it has to do something with predictability, obviously, as the seed is defined by the using code. The intention must be to get reproducibe results, at least on the same machine.
If you feed detrnd
with the same seed (which is, e.g., calculated from position data, in some function), then you'll get the same result, at least on that machine. I don't understand why that's needed, though. There must be reason for it.
Can you point me to where these colors are calculated, please?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem with As for a |
Here I'm guessing that my way of testing this was stupid: I moved So yes, I will switch back to |
Given your current implementation, yeah, that'll do. It's anyway best practice to include headers only where needed, in the smallest possible unit. |
6755c26
to
2dc19ba
Compare
The reason behind such rename was because rndscale() is just rnd(), but it generates a floating point number instead: rename the function, as it is not necessarily related to scaling of any kind.
tmprnd() replaces the old randomMT() function, which gave a random unsigned int as a result. The algorithm itself has been replaced by STL's std::mt19937, but tmprnd() allows us to obtain an unsigned int like before.
Should address #191
Picked ranlux because it seems faster (and is less predictable) but any PRNG should do
EDIT: mt19937 is back again