The following would be handy for keeping values within a specific range. There are obviously different approaches to these - but the ones I know have poor “randomness” (therefore would rather not provide code).
Random::nextInt (int min, int max);
Random::nextInt64 (int min, int max);
Random::nextFloat (int min, int max);
Random::nextDouble (int min, int max);
Well… I never added any methods like that because they didn’t really seem to add much value. Given the choice between:
x = Random::nextInt (100) + 100;
x = Random::nextInt (100, 200);
…I’d personally always go for the first one because to anyone reading it, it’s unambiguous. In the second example, it’s not obvious whether the second parameter is a maximum or a range… (and what happens if the second value is lower than the first?)
Keep it simple, I reckon! And if you find yourself making so many calls to nextInt that you’d find the extra method helpful, then it’s probably a sign that you need to D.R.Y. your code, rather than being a sign that the Random class needs more features.
I understand what you meant, but the example you gave are not obvious to me either. nextInt means, for me, next integer (so it’s signed).
Not giving any argument, I’d understand it. But with only one argument, it’s not obvious what it means, without looking the doc. With both argument, it’s clear.
Why would the first side of the range be 0, and not -arg ? (in that case, nextInt(100) could return -99 or 99)
Are they inclusive or exclusive ?
So, I’m for adding a new method “double betweenIncl(double min, double max)” and let the user understand more clearly. If the max is < min, then you’d swap both min and max.
Also, one point in the OP remark which is important to me, is the way the value are distributed in the given range. One could expect a gaussian distribution around the mid-point, another one would expect a really linear output (with P(x) = 1/range).
I’ve seen code that’s doing “while(rand < min || rand > max) rand = randomInt();”, which is clearly very bad, as it’s very predictive (not random).
Maybe it doesn’t add “value” as you see fit, but to me it does give an extra air of readability.
I personally find the second example more readable and intuitive than the first. (I wouldn’t have suggested such otherwise…) And to be perfectly honest, I’m not sure if your example is a good one; is the “+100” a subtraction of 200 - 100, or is it the minimum value? Thus, this LOC would require an additional comment to further clarify. The second example still proves better to me since it hides such details.
If the param name is written “maximum”, it should be interpreted as such, shouldn’t it? (ie: Self-documenting code) Along with well written doxygen comments, I doubt there would be a problem at all.
If the params are flipped, you could call the nextVal (min, max) method again with the max value as the min, and the min as the max? But there’s also the issue of what to do when min and max are the same…
Wouldn’t DRYing my code mean adding some method somewhere doing exactly what I suggested in order to not repeat myself?
Giving the method a better name would help, but the parameter names are irrelevant because I’m talking about what it’s like when you see the method being used in some code, when you can’t see the parameter names and probably don’t want to bother looking them up.
Yes! Precisely! But you wouldn’t call it “randomIntBetween”!
…which is slightly better. But even better would be this:
static int generateRandomAnimalHeight (int minHeightInCentimeters, int maxHeightInCentimeters)
jassert (maxHeightInCentimeters < giraffeHeight); // domain-specific sanity-check is possible here
return Random::nextInt (maxHeightInCentimeters - minHeightInCentimeters) + minHeightInCentimeters;
createAnimal (generateRandomAnimalHeight (100, 200)); // much more readable than a generic function call with some numbers.
createAnimal (generateRandomAnimalHeight (120, 300));
createAnimal (generateRandomAnimalHeight (320, 300));
Of course I might be doing you a huge disservice in assuming your code is anything like this! (And TBH I’m not even totally opposed to your suggestion!) I’m just saying that if I found myself wanting a function like that, it’d trigger internal alarm bells, and I’d think very hard about whether I was missing the bigger picture.
I don’t see the alarm bells in a situation where randomness is required within specific values or within a range (ie: Who wants a giraffe’s height to be 0, or dare I say, negative? Would make for a humorous bug, no doubt.). If I’ve understood correctly, I do now see what you mean by “value”; it would be more sensible to keep such a feature specific to, or in the scope of, the user-programmer case, for the simple fact of clarifying the situation - why it’s needed (ie: generateRandomAnimalHeight()).
juce::Random() should just produce random numbers.
There is, however, a need for constraining random numbers to a particular range. Unfortunately the straightforward approach (modulus operator) does not yield an even distribution. It would be helpful to build a new class or classes to front-end juce::Random and provide various common distributions.