5nefarious
5nefarious

Reputation: 345

Conversion from unsigned long long to unsigned int in C++

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

Answers (4)

5nefarious
5nefarious

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

Jonathan Mee
Jonathan Mee

Reputation: 38919

Good news you're safe:

  1. I just ran time.time_since_epoch().count() and got:

1,465,934,400

  1. You've got a while till you have till you see a repeat value since `numeric_limits is:

4,294,967,295

  1. Copying to a integral type of a smaller size:

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

Justin R.
Justin R.

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

user1084944
user1084944

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

Related Questions