On Mon 18 Feb, Richard Proctor wrote:
> 
> The rand function in the current riscos perl is based on the C
> function "rand", which is well known to be less the ideal.

Less than ideal? That's rather an understatement. Did you run
the program I attached which plots a graph of its distribution?
>From the graph it is clear that the probability of getting a
value in the middle of rand's range is around about a *quarter*
of the probability of getting values at the two extremes of
its range. Now I don't think you could describe that as
anything less than an unmitigated disaster!

> if/when we move riscos perl to the more recent version which
> uses the C fucntion rand48 which is more random.

I really don't think the problem with Perl's rand has anything
to do with any minor randomness failings in C's rand. I have
written an equivalent test program in C and it is clear from
the graph that whatever failings C's rand might have, it is
at least approximately uniform. The same goes for C's
_ANSI_rand() function which is supposed to be even less
good. I have also tested Perl's rand function on various
Unix boxes and found that it behaves properly. In comparison,
RISC OS Perl's rand function is *so* broken that I can only
think that there's a bug in the way it was implemented.

[Re: alternative random function]
> Go ahead post it.

Okay, thanks, here you go:

{
    my @q; # Holds random number queue

    # init_random() parameters:
    # Either a number to use as a seed
    # or none to seed on PID and time

    sub init_random (;$) {
        my $seed = shift;

        if (defined $seed) {
            srand $seed;
        } else {
            srand(($$ + ($$ << 15)) ^ time);
        }
        @q = ();
        push @q, int rand(1 << 31) while @q < 55;
    }

    # random() parameters:
    # Either a multiplier $mul for an int between 0<=x<$mul
    # or none for a float between 0<=x<1,
    # See Knuth vol 2 sec 3.2.2 eq 7 for the algorithm used

    sub random (;$) {
        my $mul = shift;

        init_random unless @q;
        my $next = ($q[-24] + $q[-55]) % (1 << 31);
        push @q, $next;
        shift @q;
        if (defined $mul) {
            return int $next / (1 << 31) * $mul;
        } else {
            return $next / (1 << 31);
        }
    }
}

Hope that's helpful to someone... :-)

-- 
James Taylor <[EMAIL PROTECTED]>
Based in Southam, Cheltenham, UK.
PGP key available ID: 3FBE1BF9
Fingerprint: F19D803624ED6FE8 370045159F66FD02

Reply via email to