/usr/games/random bug?
Peter Wemm
peter at wemm.org
Wed Dec 22 23:25:36 PST 2004
On Monday 20 December 2004 05:13 pm, James R. Van Artsalen wrote:
> 5-stable "/usr/games/random -e 99" seems to always return 0, which
> makes it very predictable.
>
> 5.2.1 does this too. But i386 4.x seems to work as expected (an exit
> value between 0 and 98 inclusive).
>
> The source code line in question is
>
> return (int)((denom * random()) / LONG_MAX);
>
> the assembler code is
>
> .p2align 3
> .LC17:
> .long 0
> .long 1006632960
>
> call random
> cvtsi2sdq %rax, %xmm0
> mulsd 24(%rsp), %xmm0
> mulsd .LC17(%rip), %xmm0
> cvttsd2si %xmm0, %eax
> jmp .L1
>
> I'm not familiar enough with IEEE fp rules or amd64 fp coding to say
> why this doesn't work, nor if this source code is even reasonable.
The problem is a code design error and/or invalid assumptions about the
range of values that random() returns..
random() returns a long.
However, random()'s range is limited to 31 bits.
"DESCRIPTION
The random() function uses a non-linear additive feedback random number
generator employing a default table of size 31 long integers to return
successive pseudo-random numbers in the range from 0 to (2**31)-1. The
period of this random number generator is very large, approximately
16*((2**31)-1)."
Now, We're taking a 2^31 bit number, and multiplying it by some integer
value, eg: 99.
Then dividing the result by LONG_MAX, which is 2^62.
Now, the result of (large but not so large number) divided by (much
larger number (a billion times larger!)) is always = 0.
Try changing the LONG_MAX in that division to INT_MAX and it will behave
the same as on i386.
Then we have (n * (0 .. 2^31)) / (2 ^ 31) which makes much more sense.
And it even works on both 32 and 64 bit systems.
--
Peter Wemm - peter at wemm.org; peter at FreeBSD.org; peter at yahoo-inc.com
"All of this is for nothing if we don't go to the stars" - JMS/B5
More information about the freebsd-amd64
mailing list