Tcl Source Code

Artifact [2091be289d]
Login

Artifact 2091be289dae21106517f2fb15d8266a20416d35:

Attachment "None" to ticket [402781ffff] added by dgp 2000-12-11 23:26:32.
Index: generic/tclExecute.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclExecute.c,v
retrieving revision 1.17
diff -c -r1.17 tclExecute.c
*** generic/tclExecute.c	2000/12/10 03:26:04	1.17
--- generic/tclExecute.c	2000/12/11 16:23:24
***************
*** 4050,4060 ****
      register int stackTop;	/* Cached top index of evaluation stack. */
      Interp *iPtr = (Interp *) interp;
      double dResult;
!     int tmp;
  
      if (!(iPtr->flags & RAND_SEED_INITIALIZED)) {
  	iPtr->flags |= RAND_SEED_INITIALIZED;
  	iPtr->randSeed = TclpGetClicks();
      }
      
      /*
--- 4050,4070 ----
      register int stackTop;	/* Cached top index of evaluation stack. */
      Interp *iPtr = (Interp *) interp;
      double dResult;
!     long tmp;			/* Algorithm assumes at least 32 bits.
! 				 * Only long guarantees that.  See below. */
  
      if (!(iPtr->flags & RAND_SEED_INITIALIZED)) {
  	iPtr->flags |= RAND_SEED_INITIALIZED;
  	iPtr->randSeed = TclpGetClicks();
+ 
+ 	/*
+ 	 * Make sure 1 <= randSeed <= (2^31) - 2.  See below.
+ 	 */
+ 
+         iPtr->randSeed &= (unsigned long) 0x7fffffff;
+ 	if ((iPtr->randSeed == 0) || (iPtr->randSeed == 0x7fffffff)) {
+ 	    iPtr->randSeed ^= 123459876;
+ 	}
      }
      
      /*
***************
*** 4067,4077 ****
       * Generate the random number using the linear congruential
       * generator defined by the following recurrence:
       *		seed = ( IA * seed ) mod IM
!      * where IA is 16807 and IM is (2^31) - 1.  In order to avoid
!      * potential problems with integer overflow, the  code uses
!      * additional constants IQ and IR such that
       *		IM = IA*IQ + IR
!      * For details on how this algorithm works, refer to the following
       * papers: 
       *
       *	S.K. Park & K.W. Miller, "Random number generators: good ones
--- 4077,4096 ----
       * Generate the random number using the linear congruential
       * generator defined by the following recurrence:
       *		seed = ( IA * seed ) mod IM
!      * where IA is 16807 and IM is (2^31) - 1.  The recurrence maps
!      * a seed in the range [1, IM - 1] to a new seed in that same range.
!      * The recurrence maps IM to 0, and maps 0 back to 0, so those two
!      * values must not be allowed as initial values of seed.
!      *
!      * In order to avoid potential problems with integer overflow, the
!      * recurrence is implemented in terms of additional constants
!      * IQ and IR such that
       *		IM = IA*IQ + IR
!      * None of the operations in the implementation overflows a 32-bit
!      * signed integer, and the C type long is guaranteed to be at least
!      * 32 bits wide.
!      *
!      * For more details on how this algorithm works, refer to the following
       * papers: 
       *
       *	S.K. Park & K.W. Miller, "Random number generators: good ones
***************
*** 4087,4100 ****
  #define RAND_IR		2836
  #define RAND_MASK	123459876
  
-     if (iPtr->randSeed == 0) {
- 	/*
- 	 * Don't allow a 0 seed, since it breaks the generator.  Shift
- 	 * it to some other value.
- 	 */
- 
- 	iPtr->randSeed = 123459876;
-     }
      tmp = iPtr->randSeed/RAND_IQ;
      iPtr->randSeed = RAND_IA*(iPtr->randSeed - tmp*RAND_IQ) - RAND_IR*tmp;
      if (iPtr->randSeed < 0) {
--- 4106,4111 ----
***************
*** 4102,4115 ****
      }
  
      /*
!      * On 64-bit architectures we need to mask off the upper bits to
!      * ensure we only have a 32-bit range.  The constant has the
!      * bizarre form below in order to make sure that it doesn't
!      * get sign-extended (the rules for sign extension are very
!      * concat, particularly on 64-bit machines).
       */
  
-     iPtr->randSeed &= ((((unsigned long) 0xfffffff) << 4) | 0xf);
      dResult = iPtr->randSeed * (1.0/RAND_IM);
  
      /*
--- 4113,4122 ----
      }
  
      /*
!      * Since the recurrence keeps seed values in the range [1, RAND_IM - 1],
!      * dividing by RAND_IM yields a double in the range (0, 1).
       */
  
      dResult = iPtr->randSeed * (1.0/RAND_IM);
  
      /*
***************
*** 4256,4266 ****
      }
      
      /*
!      * Reset the seed.
       */
  
      iPtr->flags |= RAND_SEED_INITIALIZED;
      iPtr->randSeed = i;
  
      /*
       * To avoid duplicating the random number generation code we simply
--- 4263,4278 ----
      }
      
      /*
!      * Reset the seed.  Make sure 1 <= randSeed <= 2^31 - 2.
!      * See comments in ExprRandFunc() for more details.
       */
  
      iPtr->flags |= RAND_SEED_INITIALIZED;
      iPtr->randSeed = i;
+     iPtr->randSeed &= (unsigned long) 0x7fffffff;
+     if ((iPtr->randSeed == 0) || (iPtr->randSeed == 0x7fffffff)) {
+ 	iPtr->randSeed ^= 123459876;
+     }
  
      /*
       * To avoid duplicating the random number generation code we simply
Index: tests/expr-old.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/expr-old.test,v
retrieving revision 1.9
diff -c -r1.9 expr-old.test
*** tests/expr-old.test	2000/05/09 00:00:36	1.9
--- tests/expr-old.test	2000/12/11 16:23:25
***************
*** 825,830 ****
--- 825,836 ----
  test expr-old-32.51 {math functions in expressions} {
      list [catch {expr {srand([lindex "6ty" 0])}} msg] $msg
  } {1 {argument to math function didn't have numeric value}}
+ test expr-old-32.52 {math functions in expressions} {
+     expr {srand(1<<37) < 1}
+ } {1}
+ test expr-old-32.53 {math functions in expressions} {
+     expr {srand((1<<31) - 1) > 0}
+ } {1}
  
  test expr-old-33.1 {conversions and fancy args to math functions} {
      expr hypot ( 3 , 4 )