ActiveState Code

Recipe 143083: Normally Distributed Random Numbers


This recipe produces random numbers from a normal (bell-shaped) distribution. (The rand() command in Tcl produces uniformly distributed random numbers.)

Tcl
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# The following procedure generates two independent normally distributed 
# random numbers with mean 0 and vaviance stdDev^2.  If you only need 1
# random number, choose either one.

proc randNormal {stdDev} {
    global dRandNormal1
    global dRandNormal2

    set u1 rand()
    set u2 rand()

    set dRandNormal1 [expr $stdDev * sqrt(-2 * log($u1)) * cos(2 * 3.14159 * $u2)]
    set dRandNormal2 [expr $stdDev * sqrt(-2 * log($u1)) * sin(2 * 3.14159 * $u2)]
}

# The following code is only used to demonstrate the procedure and should
# be replaced by your own code.

for {set i 1} {$i<10} {incr i} {
	randNormal 1
	puts $dRandNormal1
	puts $dRandNormal2
}

Discussion

This recipe is useful when you need random numbers from a normal distribution, such as simulating measurement noise. This solution is a very simple, straightforward way to convert Tcl's uniformly distributed random numbers to normally distributed random numbers. If you want to use this for Monte Carlo simulation you should pre-process rand() as described at http://mini.net/tcl/1551

Comments

  1. 1. At 4:06 p.m. on 21 aug 2002, andreas kupries said:

    I am not sure why the commands

    set u1 rand()
    
    set u2 rand()
    

    are there. Semantically they have no effect. The code in the recipe is equivalent to

    set dRandNormal1 [expr {$stdDev * sqrt(-2 * log(rand())) * cos(2 * 3.14159 * rand())}]
    
    set dRandNormal2 [expr {$stdDev * sqrt(-2 * log(rand())) * sin(2 * 3.14159 * rand())}]
    
  2. 2. At 11:06 a.m. on 5 sep 2002, William Kappele (the author) said:

    Code Explanation. u1 and u2 need to be the same in both calculations, so I chose them up front. If you don't keep them the same, there is no guarantee that the normal random numbers will be independent.

    Bill Kappele (bill@mathoptions.com)

  3. 3. At 11:25 a.m. on 5 sep 2002, William Kappele (the author) said:

    Code Correction. Thank you, Andreas. The code should read

    set u1 [expr rand()] set u2 [expr rand()]

    to function correctly.

  4. 4. At 5:03 p.m. on 12 sep 2003, Kregg Kemper said:

    Need to be the same. Need a third variable to make both the same

    set temp [expr rand()]

    set u1 $temp

    set u2 $temp

  5. 5. At 1:21 a.m. on 30 mar 2004, Matej Kristan said:

    Two variables. I believe two variables are needed. I am not familiar with the current language you are using, but the variables in the formulas must be uncorrelated to provide gaussian like distribution. i.e.:

    a = rand_0_1() ;

    b = rand_0_1() ;

    y1 = sigma * sqrt(-2.0 * a )*cos(2.0 * pi * b ) ;

    y2 = sigma * sqrt(-2.0 * a )*sin(2.0 * pi * b ) ;

    the random numbers y1 and y2 are now orthogonal and normally distributed. I think.

Sign in to comment