Reputation: 345
If I write the following code in C/C++:
using namespace std::chrono;
auto time = high_resolution_clock::now();
unsigned long long foo = time.time_since_epoch().count();
unsigned bar = foo;
Which bits of foo are dropped in the conversion to unsigned int? Is there any way I can enforce only the least significant bits to be preserved?
Alternatively, is there a simple way to hash foo into an unsigned int size? (This would be preferred, but I'm doing all of this in an initializer list.)
EDIT: Just realized that preserving the least significant bits could still allow looping. I gues hashing is what I'd be going for then.
2nd EDIT: To clarify what I responded in a comment, I am seeding std::default_random_engine inside a loop and do not want an overflow to cause seed values to repeat. I am looking for a simple way to hash unsigned long long into unsigned int.
Upvotes: 2
Views: 3677
Reputation: 345
Okay, I've settled on using std::hash
.
std::hash<long long> seeder;
auto seed = seeder(time.time_since_epoch().count());
Since I am doing this in an initializer list, this can be put together in one line and passed to std::default_random_engine
(but that looks pretty ugly).
This is quit a hit to performance, but at least it reduces the chance of seeds repeating.
Upvotes: 1
Reputation: 38919
Good news you're safe:
time.time_since_epoch().count()
and got:1,465,934,400
4,294,967,295
Causes dropping of excess higher order bits
So if you just do static_cast<unsigned int>(foo)
you won't get a matching output for roughly 136 years: numeric_limits<unsigned int>::max / 60U / 60U / 24U / 356U
PS You won't care if you get a repeat by then.
Upvotes: 2
Reputation: 24031
Replying to the question in edit two, you can seed based on the delta between when you started and when the seed is needed. E.g.:
std::default_random_engine generator;
typedef std::chrono::high_resolution_clock myclock;
myclock::time_point beginning = myclock::now();
for (int i = 0; i < 128; i++) // or whatever type of loop you're using
{
// obtain a seed from the timer
myclock::duration d = myclock::now() - beginning;
unsigned seed = d.count();
generator.seed(seed);
// TODO: magic
}
Upvotes: 1
Reputation:
Arithmetic with unsigned integral types in C and in C++ deals with out of range values by modular reduction; e.g. if unsigned int
is a 32 bit type, then when assigned a value out of range, it reduces the value modulo 2^32
and stores the least nonnegative representative.
In particular, that is exactly what the standard mandates when assigning from a larger to a smaller unsigned integral type.
Note also that the standard doesn't guarantee the size of unsigned int
— if you need, for example, a type that is definitely exactly 32 bits wide, use uint32_t
.
Upvotes: 6