LAB 11


Objectives


TASK

Given an integer N and a range [min,max); i.e. min included and max excluded, we like to generate N randomly-selected real numbers in that range. The selection can be done either uniformly (with all numbers in the range equally likely to be selected) or normally with a given average and standard deviation.

In order to fully understand and visualize the distribution of the generated numbers, we break the (min, max) range into smaller subintervals, call them bins and compute the percentage of our numbers that fall in each. These percentages can be printed, or better yet, plotted.

In this lab, we want to develop a structured system to address the above requirement in a flexible and comprehensive way. The system should be designed so that no implicit assumptions are made re the number of numbers, their range, nor the width of each bin. We will assume, and hard-code, however, that the number of bins is 50 and that N does not exceed 100,000. Here is a sample log of how this sought system should run:

 How many numbers to generate?
 100000
 Range: Enter the min and max values ...
 -1000. 5000.
 Enter distribution type: 1=UNIFORM (default), 2=NORMAL
 2
 Enter average and standard deviation
 1500. 600.


          8%  |                    *
          7%  |                  *****
          6%  |                 *******
          5%  |                **********
          4%  |               ************
          3%  |              **************
          2%  |            *****************
          1%  |           ********************
          0%  |**************************************************
              |--------------------------------------------------
          -1000.                                             5000.

As you can see, all the parameters (except the number of bins) are entered by the user. The final output is a Fortran-generated chart (i.e. not from Excel) that plots the computed percentages versus the 50 bins. The chart has the following characteristics:

Here is the main program:

program Lab11
implicit none
real*4 A(100000), min, max
integer*4 N, bin(50), binCount
logical*1 ok
binCount = 50
!--------------------------------------------------------------------
call GetData(A, N, min, max, ok)
if (.NOT. ok) then
   print*, "Invalid entries!  Program aborted."
else
   call Group(A, N, bin, binCount, min, max)
   call ShowData(N, bin, binCount, min, max)
end if
!--------------------------------------------------------------------
end

The subroutine GetData has the following header:

subroutine GetData(A, N, min, max, ok)
implicit none
integer*4 N
real*4 A(100000), MyRandom, avg, std, min, max
logical*1 ok

It prompts the user to enter the number of numbers to generate (N), their range (min and max), distribution type (1 for uniform or 2 for normal), and for type=2, the average and standard deviation. It validates the entries to ensure N is positive and not greater than 100,000, and that min is less than max. It then uses the MyRandom function (below) to generate the desired numbers and place them in array A and return.

The function MyRandom has the following header:

real*4 Function MyRandom(min, max, avg, std, type)
implicit none
real*4 min, max, avg, std, x, rand
integer*4 type
It returns one real*4 random number in the specified range having the specified distribution type. The SLATEC library has routines for both uniformly ad normally distributed numbers. Once a number x is generated it should clipped and returned. Clipping is needed in order to satisfy the min / max requirement as follows:

if (x .LT. min) then
   x = min
else if (x .GE. max) then
   x = max - 0.000001
end if

Subroutine Group receives N elements in A and it must populate the binCount elements of array bin by counting how many of the elements of A fall in each of its intervals. bin(1) contains a count of the elements in A that are grater or equal to min and less than min+width, where width =(max-min)/binCount is the width of each bin. Similarly, bin(2) contains a count of the elements in A that are grater or equal to min+width but less than min+2*width, and so on. The subroutine must start by initializing all elements in array bin to zero (since they are counters) and then scan the array A once. When one of its elements, i, is visited, a decision has to be made as to which interval it belongs to, and hence, which element of bin should be incremented.

Subroutine ShowData generates the chart and has the following header:

subroutine ShowData(N, bin, binCount, min, max)
implicit none
integer*4 N, binCount, bin(binCount)
real*4 min, max
It creates a 2-dimensional array of 100 rows and 50 columns with each element being a character*1; e.g.
  character*1 chart(0:100, 0:50)
where coloumn zero corresponds to the y-axis (where a vertical bar, or pipe is displayed), and row zero corresponds to the first row above the x-axis. The columns correspond to the bins and the rows to the percents. We adopt the convention that a percent greater or equal to zero and less than 1 is mapped to row#0, and so on. A percent equal to 100% (or 1) is mapped to row#100.

Initialize the array so that all elements are blanks except all elements at column zero have a pipe character. Determine the highest percentage so that you can restrict the y-axis to the data. To print row #i, use a statement like:

	print*, (chart(i,j), j=0, binCount)
Add formatting as needed.

To check this lab, generate a listing of the source code of your completed system together with a number of test cases. You can re-direct the output of ShowData to a disk file.


Fall2002/HR