tech-userlevel archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: mrand48 broken on 64-bit systems
On Oct 21, 2013, at 5:44 PM, enh <enh%google.com@localhost> wrote:
> The mrand48() and jrand48() functions return signed long integers
> uniformly distributed over the interval [-2**31,2**31].
> http://pubs.opengroup.org/onlinepubs/7990989799/xsh/drand48.html
>
> the freebsd, netbsd, and openbsd mrand48 implementations all just
> assume that long is 32-bit, and are thus broken on 64-bit
> architectures. (found running Android's bionic unit tests on x86_64.)
>
> a cast appears to be all that's missing (though i don't know whether
> you support architectures where sizeof(int) != 4, in which case you'll
> want int32_t instead):
>
> diff --git a/libc/upstream-netbsd/libc/stdlib/mrand48.c
> b/libc/upstream-netbsd/libc/stdlib/mrand48.c
> index c787ce6..b1083a1 100644
> --- a/libc/upstream-netbsd/libc/stdlib/mrand48.c
> +++ b/libc/upstream-netbsd/libc/stdlib/mrand48.c
> @@ -29,5 +29,5 @@ long
> mrand48(void)
> {
> __dorand48(__rand48_seed);
> - return ((long) __rand48_seed[2] << 16) + (long) __rand48_seed[1];
> + return (int) ((long) __rand48_seed[2] << 16) + (long) __rand48_seed[1];
> }
It seems at first glance it would make more sense to replace the longs
by int32_t and avoid the 64-bit ops on LP64. Alas, it's more subtle than
that. For jrand48/mrand48 which return signed int32s, the easiest and
cleanest fix to change the return to:
return (int16_t)__rand48_seed[2] * 65536 + __rand48_seed[1];
The multiple causes promotion to int and thus the int will be sign
extended to long if needed. Let the compiler optimize the multiply to
a shift. lrand/nand returns change to:
return __rand48_seed[2] * 32768 + (__rand48_seed[1] >> 1);
And all casts go away. the multiply promotes everything to unsigned int.
Home |
Main Index |
Thread Index |
Old Index