[gnu.ghostscript.bug] Problems in rand

ath@helios.prosys.se (Anders Thulin) (03/28/89)

The random number generator in GhostScript 1.2 occasionally returns
negative numbers.

The reason appear to be that the routine zrand() in zmath.c calls
rand(), and does some juggling to avoid propagating the non-randomness
in rand().

A possible patch would be to do something like:

	value &= 0x7FFFFFFF;

but I wouldn't swear on the resulting generator being sufficiently
random. Another approach would be to change to nrand48(). This
would have the added benefit of avoiding possibly long loops in
zsrand().

Suggested patches:
*** zmath.old.c	Fri Feb 24 09:11:39 1989
--- zmath.c	Tue Mar 28 10:17:40 1989
***************
*** 32,45 ****
  double degrees_to_radians = M_PI / 180.0;
  double radians_to_degrees = 180.0 / M_PI;
  
! /* Iteration count for random number generator */
! static long rand_count;
  
  /* Initialize the random number generator. */
  void
  zmath_init()
! {	rand_count = 0;
! 	srand(1);
  }
  
  /****** NOTE: none of these operators currently ******/
--- 32,44 ----
  double degrees_to_radians = M_PI / 180.0;
  double radians_to_degrees = 180.0 / M_PI;
  
! /* Current seed for random number generator */
! static unsigned short rand_seed[3] = {0,};
  
  /* Initialize the random number generator. */
  void
  zmath_init()
! {	rand_seed[0] = rand_seed[1] = rand_seed[2] = 0;
  }
  
  /****** NOTE: none of these operators currently ******/
***************
*** 166,176 ****
  int
  zrand(register ref *op)
  {	long value;
! 	/* The Unix man page for rand suggests dropping the lowest bits, */
! 	/* so that's effectively what we do here. */
! 	value = (long)rand() << 21;
! 	value += (long)rand() << 10;
! 	value += rand() >> 3;
  	push(1);
  	make_int(op, value);
  	return 0;
--- 165,171 ----
  int
  zrand(register ref *op)
  {	long value;
! 	value = nrand48(rand_seed);
  	push(1);
  	make_int(op, value);
  	return 0;
***************
*** 179,190 ****
  /* srand */
  int
  zsrand(register ref *op)
! {	long niter;
  	check_type(*op, t_integer);
! 	niter = op->value.intval;
! 	rand_count = niter;
! 	srand(1);
! 	while ( niter-- ) rand(), rand(), rand();
  	pop(1);
  	return 0;
  }
--- 174,185 ----
  /* srand */
  int
  zsrand(register ref *op)
! {	long seed;
  	check_type(*op, t_integer);
! 	seed = op->value.intval;
! 	rand_seed[0] = seed >> 16;
! 	rand_seed[1] = seed & 0xFFFF;
! 	rand_seed[2] = 0x330E;
  	pop(1);
  	return 0;
  }
***************
*** 193,199 ****
  int
  zrrand(register ref *op)
  {	push(1);
! 	make_int(op, rand_count);
  	return 0;
  }
  
--- 188,194 ----
  int
  zrrand(register ref *op)
  {	push(1);
! 	make_int(op, (rand_seed[0]<<16) + rand_seed[1]);
  	return 0;
  }
  
***************
*** 218,220 ****
--- 213,216 ----
  	};
  	z_op_init(my_defs);
  }
+ 
- - - - - - - end of patches - - - - -
-- 
Anders Thulin			INET : ath@prosys.se
ProgramSystem AB		UUCP : ...!{uunet,mcvax}!enea!prosys!ath
Teknikringen 2A			PHONE: +46 (0)13 21 40 40
S-583 30 Linkoping, Sweden	FAX  : +46 (0)13 21 36 35