Author: Dieter Buerssner
Date: 22:24:20 12/14/01
Go up one level in this thread
On December 15, 2001 at 00:10:00, Paul Byrne wrote:
>Not sure if it is the compiler that is stupid or the question... :)
>
>When I started using the MS compiler recently I discovered that rand()
>is only 16 bits & just hacked this together to get things running...
>[yes, I know rand() is evil, but ignore that for a moment :)]
>
>unsigned rand32()
>{
> return (unsigned) (rand() ^ (rand()<<7) ^ (rand()>>7) ^
> (rand()<<17) ^ (rand()>>17) ^ (rand()<<23) ^ (rand()>>23));
>}
>
>Problem is, this returns different things in debug and release mode,
>which stops my opening books from functioning in debug mode.
>rand() is returning the same sequence of integers, so I'm assuming
>the optimizer is messing with the order of the calls (I'm just using
>the default maximize speed settings).
>
>Shouldn't the ^ operator always be left to right?
>
>Am I missing something here, or is the compiler breaking the rules? :)
You code is unspecified behaviour.
From the C Standard:
6.5 Expressions
[...]
3 The grouping of operators and operands is indicated by the syntax.61) Except
as specified later (for the function-call (), &&, ||, ?:, and comma operators),
the order of evaluation of subexpressions and the order in which side effects
take place are both unspecified.
From my rather old version of the comp.lang.c FAQ:
4.5: Can I use explicit parentheses to force the order of evaluation
I want? Even if I don't, doesn't precedence dictate it?
A: Operator precedence and explicit parentheses impose only a
partial ordering on the evaluation of an expression. Consider
the expression
f() + g() * h()
-- although we know that the multiplication will happen before
the addition, there is no telling which of the three functions
will be called first.
I can add: You can force the order of evaluation by using several expressions.
So in
unsigned long k, l, m;
k = rand();
l = rand();
m = (k + l) - rand();
the order of evaluation is specified, while in
m = (rand() + rand()) - rand();
it is not.
You could try the following PRNG. It is small and fast and shows reasonable
results in test for randomness. I think, it is also much less hazzle and error
prone,
than using rand().
static unsigned long zs = 0x12345678UL;
static unsigned long ws = 0x87654321UL;
/* Multiply with carry RNG. Pastes together 2 16 bit MWC generators.
Suitable multipliers (list from Fortran source of Marsaglia):
:: 18000 18030 18273 18513 18879 19074 19098 19164 19215 19584 ::
:: 19599 19950 20088 20508 20544 20664 20814 20970 21153 21243 ::
:: 21423 21723 21954 22125 22188 22293 22860 22938 22965 22974 ::
:: 23109 23124 23163 23208 23508 23520 23553 23658 23865 24114 ::
:: 24219 24660 24699 24864 24948 25023 25308 25443 26004 26088 ::
:: 26154 26550 26679 26838 27183 27258 27753 27795 27810 27834 ::
:: 27960 28320 28380 28689 28710 28794 28854 28959 28980 29013 ::
:: 29379 29889 30135 30345 30459 30714 30903 30963 31059 31083 ::
my [Marsaglia] favorites are 18000, 30963
*/
unsigned long mwc1616(void)
{
unsigned long t = zs;
zs = 30903*(t&0xffff)+(t>>16);
t = ws;
ws=18000*(t&0xffff)+(t>>16);
return ((ws&0xffff)<<16) + (zs&0xffff);
}
BTW. Many systems don't have 16 bit rand(), but rather 15 bit rand().
Regards,
Dieter
This page took 0 seconds to execute
Last modified: Thu, 15 Apr 21 08:11:13 -0700
Current Computer Chess Club Forums at Talkchess. This site by Sean Mintz.