问题
I have an array with 7 elements and I'm trying to get a random number between 0 - 6 so I can select an element in the array at random.
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
class Color{
public:
Color(){
colors[0] = "red";
colors[1] = "orange";
colors[2] = "yellow";
colors[3] = "green";
colors[4] = "blue";
colors[5] = "indigo";
colors[6] = "violet";
}
void printColors()
{
for (int i = 0; i<sizeof(colors)/sizeof(colors[0]); ++i)
{
cout << colors[i] << endl;
}
}
void printRandomColor()
{
int random_integer = rand() % 7;
cout << random_integer << endl;
}
private:
string colors[7];
};
int main(int argc, const char * argv[]) {
srand( static_cast<unsigned int>(time(0)));
Color colorObject;
colorObject.printRandomColor();
return 0;
}
When I do rand() % 7 I keep getting 6, but if I do rand() % 6 I end up getting random numbers. What gives?
I call srand( static_cast<unsigned int>(time(0))); in my main()
回答1:
I noticed the same behavior with the code shown in the question:
rand() % 7 // always shows 6
rand() % 14 // always shows 6 or 13
rand() % 21 // always shows 6, 13, or 20
The problem is peculiar and there seems to be a pattern involved. Based on the comments that some aren't able to reproduce it, I decided to compile the code, with gcc on a Linux based machine and clang on macOS; Linux seems to behave normally from what I can tell, however macOS does not. I even tried completely different code just make sure it wasn't something else, yet got the same result.
#include <cstdlib>
#include <iostream>
#include <ctime>
int main()
{
int min = 1;
int max = 7;
std::srand(std::time(0)); // use current time as seed for random generator
// int random_variable = std::rand() % max; // always returns 6
// int random_variable = std::rand() % (max - min) + min; // produces 'predictable' numbers based on the time.
int random_variable = RAND_MAX % std::rand() % (max-min) + min; // also returns predicate results based on the timing, except in reverse.
std::cout << "Random value on [0 " << RAND_MAX << "]: "
<< random_variable << '\n';
}
The only way I was able to get seemingly random results from rand() was to do:
RAND_MAX % std::rand() % (max-min) + min; // predictable based on timing
The issue is odd, and might be a bug with Clang; I'm at a loss at to what exactly is at play here. I would probably recommend using something other than rand() such as the <random> library mentioned in the comments perhaps.
EDIT: After reporting this bug to Apple this was the response:
Apple Developer Relations July 27 2017, 11:27 AM
There are no plans to address this based on the following:
std::rand directly uses rand from the C library. rand is known and documented to be broken (and is not going to change since people depend on its specific behavior).
From the man page: RAND(3) BSD Library Functions Manual
NAME rand, rand_r, srand, sranddev -- bad random number generator
DESCRIPTION These interfaces are obsoleted by arc4random(3).
For good pseudorandom numbers in C++, look at from C++11. E.g.: http://en.cppreference.com/w/cpp/numeric/random
Based on this information RAND() is broken and won't be fixed — use an alternative random number generator.
回答2:
rand() is terrible. rand() % range is worse. Don't use it. Use arc4random_uniform().
#include <iostream>
#include <cstdlib> // Needed for arc4random_uniform()
int main(int argc, char *argv[]) {
// Random number between 0 and 6.
std::cout << arc4random_uniform(7) << std::endl;
}
So in your case:
void printRandomColor()
{
int random_integer = arc4random_uniform(7);
cout << random_integer << endl;
}
If portability is desired, then here is a C++ standard example. To me, it's needlessly more complicated and runs slower, but hey… it's the C++ standard.
#include <iostream>
#include <random> // For std::random_device and std::uniform_int_distribution
int main() {
std::random_device randomizer;
std::uniform_int_distribution<int> distribution(0, 6);
// Random number between 0 and 6.
int random_integer = distribution(randomizer);
std::cout << random_integer << std::endl;
}
回答3:
I would like to point out, that you are using a Random (Rand) operator, then trying to find out if the result has a Remainder (%), the Result will be the Remainder, which is where your strange math comes from. This is known as the Modulo Operator or Modulus Operator if you desire to Google it, although you should know that it actually has a slightly different name in C#, there is a Post in StackTrace about it Here:
What does the '%' operator mean?
If you open the Calc.exe Windows Program it is listed in Scientific Mode (Alt+2) as Mod.
Specifically, the way % operates is ((x - (x / y)) * y)
The above URL is a direct link to my answer where I point out specifically HOW it differs from standard / complete with a long drawn out example simulating all of the math step by step, the result returns a 0 for % and a 1 for / since the / Operand does roundUp() whilst % does roundDown() from what I've understood in the other Answers in that Post.
Update
I would at least like to have this answer here to provide reference for the Modulo Operator which is mentioned in the title of this question.
I didn't post this specifically as an answer per se, but more as reference material to avoid spam posts in the future.
If this is in fact a discovered bug, then this question is going to be picked apart letter by letter, symbol by symbol, and it's going to assist everybody involved to have this reference material here.
If I didn't know already it was named Modulo/Modulus in most languages, I would wonder what he meant by "Modulo" as he never explains anywhere that the % is named exactly that.
This answer addresses the fact that % uses roundDown() whereas / uses roundUp() complete with a referenced compile-able example written painstakingly in expanded step-by-step longhand which I then converted to C#.
I also would like to reiterate, as I mentioned in the comments, I have zero knowledge about xCode, I am somewhat familiar with C# and have provided this information in the C# context which this question is tagged with.
来源:https://stackoverflow.com/questions/44742149/rand-not-giving-random-numbers-depending-on-modulo-in-xcode