From: Greg Colvin (gcolvin_at_[hidden])
Date: 2000-02-20 21:43:57


From: Jacob Hammeken <jacobh_at_[hidden]>
> Greg Colvin wrote:
> > I've been playing around with this, and made a small modification
> > so that you can vary the quality of the result by specifying nbits
> > other than 8. Also made it compile as C (:-)
> ...
> > I didn't mask off the higher bits of the counter
> ...
> > I also made a Win32-specific version that has the virtue of not
> > tying up the CPU so much:
> ...
> > QueryPerformanceCounter(&clicks);
> ...
> Unfortunately, a high-performance counter may not be available, in
> which case clicks will be 0. In that case, the return-value of
> rand_byte will also be 0. By the way, the function is not available in
> Win32s.

So much the worse for Win32s. As I recall, Win32s is still close
enough to DOS that you can just peek into some memory location
for the system clock. Maybe this is what GetTickCount() does.

> I suspect the granularity of GetTickCount (miliseconds) is way too
> coarse to be used instead of QueryPerformanceCounter, in particular
> because this is also the granularity of Sleep. But if not, perhaps one

Although on my NT box Sleep() never comes back in less than 15
milliseconds.

> could use GetTickCount instead if QueryPerformanceCounter fails?
> My documentation states the following about GetTickCount:
> >If the function succeeds, the return value is the number of
> milliseconds that have elapsed since Windows was started
> Unfortunately, it neglects to mention what happens if it does not
> succeed... I can not quite imagine why it would not succeed, but it is
> very frustrating not to know for sure.

Such frustration is the typical state of a Win32 programmer.
Too bad we can't just check the source code.
 
> It could perhaps look like this (I have only modified one line):
> unsigned char rand_byte(int nbits)
> {
> unsigned int result=0;
> int i;
> LARGE_INTEGER clicks;
> for (i=0; i<nbits; ++i) {
> Sleep(1);
> if(QueryPerformanceCounter(&clicks)==0)
> clicks.LowPart=GetTickCount();
> // rotate low byte left 1 bit and XOR in LSB of counter
> result = (((result << 1) | (result >> 7)) & 0xFF) ^
> (clicks.LowPart);
> }
> return result;
> }
>
> Alternatively, one could perhaps use a different algorithm if
> QueryPerformanceCounter fails.

Perhaps, but we are getting into pretty machine/OS specific
programming here. Even the "portable" versions based on clock()
can easily fail to produce random numbers. So the thing to do
is just test.