1

I need to implement C's drand48() and srand48() random number generator and initializer for a programming project written in Java. The program needs to mimic the generation of a pseudo random number from these functions in C given a specific seed.

According to the man pages:

All the functions work by generating a sequence of 48-bit integers, Xi, according to the linear congruential formula:

Xn+1 = (aXn + c) mod m, where n >= 0

The parameter m = 2^48, hence 48-bit integer arithmetic is performed. Unless lcong48() is called, a and c are given by:

a = 0x5DEECE66D
c = 0xB

In this srand48() implementation below, I set the high order 32-bits of Xi to the argument seedval. The low order 16-bits are set to the arbitrary value 0x330E, according to the man pages. I do not understand how to apply the congruential formula to extract a random number. Any help would be greatly appreciated, thanks!

public void srand48(long seedval) {
  this.seed = seedval & 0xFFFFFFFF;
  this.seed = (this.seed << 16) | 0x330E;
}

public double drand48() {
  this.seed = (0x5DEECE66DL * this.seed + 0xBL) & ((1L << 48) - 1);
  return this.seed;
}

The numbers that come out when drand48() is called are out of the range [0.0, 1.0). Could someone also explain why 48 bits is so significant for this pseudo random number generation?

Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
  • 1
    The original design and implementation date from an era when `int` was often 16 bits, and `long` was 32 bits, and there were no 64-bit types. The use of 48 bits was better than using just 32 bits, by quite a large margin. – Jonathan Leffler Jul 07 '19 at 23:18
  • Note that the POSIX specification for these functions ([`drand48()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/drand48.html)) goes into fair detail. But Java probably has better PRNG functions available; are you sure you want to emulate these? – Jonathan Leffler Jul 07 '19 at 23:23
  • @JonathanLeffler That makes much more sense, thank you! And this project was assigned to me in one of my classes, so I don't have control over it, unfortunately. – Chris Turgeon Jul 07 '19 at 23:48
  • @Chris If you want to have a look at the state of the art in pseudo-random number generation, here is a recent paper by K. Bhattacharjee et al. about the compared merits of various techniques, including drand48/lrand48: https://arxiv.org/abs/1811.04035 – jpmarinier Jul 08 '19 at 09:13
  • @jpmarinier I had no understanding of how these techniques worked under the hood until I had to implement drand48/srand48. Interesting stuff, and I'll give it a read, thank you! – Chris Turgeon Jul 08 '19 at 15:37

2 Answers2

2

Your implementation looks fine. The values you get are out of range because you're returning this.seed directly. You should normalize the result between 0.0 and 1.0 first, then return it. Also, make sure this.seed is a long.

The correct code would be:

public double drand48() {
    this.seed = (0x5DEECE66DL * this.seed + 0xBL) & ((1L << 48) - 1);
    return (double)this.seed / (1L << 48);
}
Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
  • 1
    In order to normalize the pseudo-random state to a floating-point value between 0.0 and 1.0, you can use the scalb() library function. Like "double xs = seed ; return Math.scalb(xs,-48);". See its specs here: https://www.tutorialspoint.com/java/lang/math_scalb_double.htm – jpmarinier Jul 07 '19 at 23:44
0

Note that in Java the first line of your srand48 initializer method has no effect. If you want to limit the value to 32 bits you need to add the 'L' prefix, i.e. 0xFFFFFFFF -> 0xFFFFFFFFL

see Why Long.toHexString(0xFFFFFFFF) returns ffffffffffffffff

neilireson
  • 409
  • 3
  • 7