time and srand

C

conrad

What kind of problems could arise if
one were to not cast the value of time()
to unsigned int? What are the sections
in the standard that provide the reasoning
of any claims against such a practice?
 
S

santosh

conrad said:
What kind of problems could arise if
one were to not cast the value of time()
to unsigned int? What are the sections
in the standard that provide the reasoning
of any claims against such a practice?

The cast is recommended since there is no implicit conversion between
unsigned and time_t. The C standard simply says that time_t is an
arithmetic type. It could be an integer or floating point type.
Therefore an explicit cast is usual when using a time_t value as seed
for srand.
 
K

Keith Thompson

santosh said:
The cast is recommended since there is no implicit conversion between
unsigned and time_t. The C standard simply says that time_t is an
arithmetic type. It could be an integer or floating point type.
Therefore an explicit cast is usual when using a time_t value as seed
for srand.

Yes, there is an implicit conversion from unsigned to time_t, as there
is between any two arithmetic types.

This:
srand(time(NULL));
and this:
srand((unsigned)time(NULL));
are equivalent, assuming you have the required "#include <time.h>".
Since the cast doesn't buy you anything, you might as well leave it
out.
 
J

James Kuyper

conrad said:
What kind of problems could arise if
one were to not cast the value of time()
to unsigned int? What are the sections
in the standard that provide the reasoning
of any claims against such a practice?

I can't see any plausible problems with not casting the value of time()
to an unsigned int.

I do see possible problems from casting it to unsigned int:

1. If time_t is a signed integer type, the conversion will not be value
preserving for negative values.

2. If time_t is a type with a maximum greater than UINT_MAX, the
conversion will lose the high-order bits.

3. If time_t is a floating point type, the conversion will loose you the
fractional part,

4. If time_t is an imaginary type, the conversion will loose 100% of the
information.

Who suggested to you that conversion to unsigned int was the proper
thing to do, and what reasons did they give?
 
S

santosh

James said:
I can't see any plausible problems with not casting the value of
time() to an unsigned int.

I do see possible problems from casting it to unsigned int:

<snip>

In light of your, Keith's, and Richard's reply I apologise to the OP for
incorrect advice.
 
K

Keith Thompson

James Kuyper said:
I can't see any plausible problems with not casting the value of
time() to an unsigned int.
Agreed.

I do see possible problems from casting it to unsigned int:

1. If time_t is a signed integer type, the conversion will not be
value preserving for negative values.

2. If time_t is a type with a maximum greater than UINT_MAX, the
conversion will lose the high-order bits.

3. If time_t is a floating point type, the conversion will loose you
the fractional part,

4. If time_t is an imaginary type, the conversion will loose 100% of
the information.

Who suggested to you that conversion to unsigned int was the proper
thing to do, and what reasons did they give?

The context, I think was
srand(time(NULL));
Since srand's argument is of type unsigned int, the conversion will
happen with or without a cast.
 
J

jameskuyper

Keith said:
The context, I think was
srand(time(NULL));
Since srand's argument is of type unsigned int, the conversion will
happen with or without a cast.

Depending upon the implementation-specific time representation used
for time_t, that expression might generate only a small number of
different seed values, or it might generate seed values that change
excessively slowly with time. What you typically need in that context
is an expression that generates a different seed value each time you
run the program, and has a roughly equal chance of generating every
permitted seed value.

To minimize dependence upon the representation of time_t, I'd
recommend something like this:

#include <limits.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

srand(fmod(difftime(0, time(NULL), UINT_MAX+1.0));

That will use different seed values at the rate of 1/second, which
should be good enough for many purposes.
 
J

jameskuyper

Depending upon the implementation-specific time representation used
for time_t, that expression might generate only a small number of
different seed values, or it might generate seed values that change
excessively slowly with time. What you typically need in that context
is an expression that generates a different seed value each time you
run the program, and has a roughly equal chance of generating every
permitted seed value.

To minimize dependence upon the representation of time_t, I'd
recommend something like this:

#include <limits.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

srand(fmod(difftime(0, time(NULL), UINT_MAX+1.0));

That will use different seed values at the rate of 1/second, which
should be good enough for many purposes.

I was thinking too hard; the fmod() is unnecessary, of course.
 
R

Richard Heathfield

(e-mail address removed) said:

To minimize dependence upon the representation of time_t, I'd
recommend something like this:

#include <limits.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

srand(fmod(difftime(0, time(NULL), UINT_MAX+1.0));

Lawrence Kirby once proposed the following alternative, which works very
nicely:

#include <limits.h>
#include <stdlib.h>
#include <time.h>


/* Choose and return an initial random seed based on the current time.
Based on code by Lawrence Kirby <[email protected]>.
Usage: srand (time_seed ()); */
unsigned
time_seed (void)
{
time_t timeval; /* Current time. */
unsigned char *ptr; /* Type punned pointed into timeval. */
unsigned seed; /* Generated seed. */
size_t i;


timeval = time (NULL);
ptr = (unsigned char *) &timeval;


seed = 0;
for (i = 0; i < sizeof timeval; i++)
seed = seed * (UCHAR_MAX + 2u) + ptr;


return seed;


}
 
C

cr88192

Depending upon the implementation-specific time representation used
for time_t, that expression might generate only a small number of
different seed values, or it might generate seed values that change
excessively slowly with time. What you typically need in that context
is an expression that generates a different seed value each time you
run the program, and has a roughly equal chance of generating every
permitted seed value.

To minimize dependence upon the representation of time_t, I'd
recommend something like this:

#include <limits.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

srand(fmod(difftime(0, time(NULL), UINT_MAX+1.0));

That will use different seed values at the rate of 1/second, which
should be good enough for many purposes.

one option I have used:
implement a custom prng, with a larger internal state, for example, 4096
bits (reason: rand does not necissarily have all that large of an internal
state, and is thus not really good for some uses);
the initialization function can load the seed from a file, use the 'time'
trick, rehash the seed or similar, and store it back out to the file (thus
each run hopefully adding a little more entropy).

if done well, with any luck, this gives at least some semblence of
randomness.

rand is useful for some things (where the actual randomness isn't all that
important, or only applies to a small range).

but, when using it for some other things, for example, generating largish
presumably unique values (GUID-like values, ...) one hopes for something
hopefully a little more 'random'.

for example, if it only has about 32 or 48 bits of entropy, what good is it
to try to generate , say, 96 bit unique values. there will be, at most (and
probably much less) 2^32 or 2^48 different values.

a slightly larger entropy, say, 2^4096, is a little more sane for this kind
of use.

or such...


now, here is another possibly interesting (mostly hypothetical) problem:
open-source copy protection.

goal: a copy protection scheme which will still work, even when the user has
full ability to look at, modify, and recompile the source (and, thus, it
can't be based on obscurity, or something which the user can simply bypass
or comment out).

I have some possible ideas here, but I will keep them to myself...
 
J

Jack Klein

I can't see any plausible problems with not casting the value of time()
to an unsigned int.

I do see possible problems from casting it to unsigned int:

No problems that do not occur without the cast to unsigned int, given
a prototype for srand() is in scope.
1. If time_t is a signed integer type, the conversion will not be value
preserving for negative values.

2. If time_t is a type with a maximum greater than UINT_MAX, the
conversion will lose the high-order bits.

3. If time_t is a floating point type, the conversion will loose you the
fractional part,

If time_t is a floating point type and the integral part of the value
is greater than UINT_MAX or less than 0, the conversion will generate
undefined behavior. With or without a cast.
4. If time_t is an imaginary type, the conversion will loose 100% of the
information.

What exactly is an imaginary type in C? They only exist as part of a
_Complex float, double, or long double. They no more exist in
isolation than do quarks.

If time_t is a _Complex type, the behavior is undefined with or
without the cast, because the standard does not define such a
conversion.

If a _Complex type is converted via an intermediary (real float,
double, or long double), then the imaginary part is simply discarded,
and the behavior is undefined if the real part of the _Complex is
outside the range of the destination floating point type.

If that succeeds, the resulting float can be converted, with or
without cast, to unsigned int as an argument to srand(). Again
producing undefined behavior if the integer part of the floating point
type is negative or greater than UINT_MAX.
Who suggested to you that conversion to unsigned int was the proper
thing to do, and what reasons did they give?

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
 
K

Keith Thompson

Jack Klein said:
On Thu, 20 Dec 2007 12:45:31 GMT, James Kuyper


What exactly is an imaginary type in C? They only exist as part of a
_Complex float, double, or long double. They no more exist in
isolation than do quarks.
[...]

_Imaginary float, _Imaginary double, or _Imaginary long double.

See C99 Annex G (which is optional).
 
J

James Kuyper

Jack said:
No problems that do not occur without the cast to unsigned int, given
a prototype for srand() is in scope.


If time_t is a floating point type and the integral part of the value
is greater than UINT_MAX or less than 0, the conversion will generate
undefined behavior. With or without a cast.


What exactly is an imaginary type in C? They only exist as part of a
_Complex float, double, or long double. They no more exist in
isolation than do quarks.

Yes, they've isolated the _Imaginary type. The "double _Imaginary" type
is a type with the same size as 'double', which can only represent
values with a real component of 0, just as ordinary 'double' can only
represent values with an imaginary component of 0. I can't imagine any
good reason for defining time_t as an imaginary type, except that it is
permitted for a conforming implementation of C, and it breaks a lot of
code that seems perfectly harmless because it wasn't written with that
possibility in mind, which could be useful for teaching purposes, if
nothing else. The really nasty possibility is that clock_t is imaginary,
which would require that CLOCKS_PER_SEC must also be imaginary.
If time_t is a _Complex type, the behavior is undefined with or
without the cast, because the standard does not define such a
conversion.

When time_t is a complex type, the following rules apply:

6.2.5p17: " ... The integer and real floating types are collectively
called real types."

Key point: integer types are real types, as far as the C standard is
concerned. That means that the citations below apply when the
destination is an integer type.

6.3.1.7p2:
"When a value of complex type is converted to a real type, the imaginary
part of the complex value is discarded and the value of the real part is
converted according to the conversion rules for the corresponding real
type."
If a _Complex type is converted via an intermediary (real float,

You don't need to explicitly specify an intermediary; the sections
listed above describe a direct conversion, that works pretty much as you
describe for the indirect conversion.

However, if time_t were an imaginary type, the rules from Annex G4.2p1
apply: "When a value of imaginary type is converted to a real type other
than _Bool,324) the result is a positive zero."
 
J

jameskuyper

Jack said:
On Thu, 20 Dec 2007 12:45:31 GMT, James Kuyper


If time_t is a floating point type and the integral part of the value
is greater than UINT_MAX or less than 0, the conversion will generate
undefined behavior. With or without a cast.

For some reason I remembered incorrectly that the modulus rules for
conversion to unsigned types applied to floating point sources as
well. Since you are correct, that means that the fmod() in my other
message was indeed necessary.
 
C

cr88192

Keith Thompson said:
Jack Klein said:
On Thu, 20 Dec 2007 12:45:31 GMT, James Kuyper


What exactly is an imaginary type in C? They only exist as part of a
_Complex float, double, or long double. They no more exist in
isolation than do quarks.
[...]

_Imaginary float, _Imaginary double, or _Imaginary long double.

See C99 Annex G (which is optional).

and, a few of us were lazy and ended up internally aliasing _Imaginary to
_Complex...

actually, at first I had implemented them as such, later noticing that GCC
had only _Complex, and thus I lacked some motivation on this front, and
later on _Complex effectively assimilated _Imaginary.


now, something even more weird:
in my upper compiler, since _Complex only applies to float types, and
'unsigned' only really applies to integer types, I ended up using the same
modifier for both (in this case, a flag).

so, in this case:
unsigned float f;
and:
float _Complex f;

come out as equivalent...


however, in the lower compiler, each type effectively has a unique type, so
there is no such aliasing at this level.
 
T

Thad Smith

Followups set to comp.programming.
now, here is another possibly interesting (mostly hypothetical) problem:
open-source copy protection.

goal: a copy protection scheme which will still work, even when the user has
full ability to look at, modify, and recompile the source (and, thus, it
can't be based on obscurity, or something which the user can simply bypass
or comment out).

What is the goal of a copy protection scheme when the user has the ability
to look at, modify, and recompile the source? What, specifically, is being
protected from what?
I have some possible ideas here, but I will keep them to myself...

You can use a public-key-based signature to demonstrate that some
particular person has approved a particular version. That doesn't prevent
copying, though.
 
G

Geoff

That's an implementation I'd like to have!

For all the language pedantry in this group, you would think they
would be better spellers.

lose, not loose.

Simple mnemonic:

To lose is lost.
Too loose is a noose.
 
J

James Kuyper

Geoff said:
For all the language pedantry in this group, you would think they
would be better spellers.

Being pedantic about other people's mistakes doesn't mean that I don't
make mistakes of my own; it just means that it's annoying when I
discover that I've made one. Still, I prefer to know about my mistakes,
rather than remaining ignorant of them.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top