- Random Numbers
- Distribution
- Fortran-generated Charts

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:

- It uses the "pipe character" (|) for the y-axis and the hyphen (-) for the x-axis.
- The y-axis is labeled with the percentages while the x-axis has only starting and ending labels (being min and max)
- The y-axis does not necessarily extend from 0% to 100%. Instead, it stops where the highest percentage reaches.
- For each bin, asterisks are used to fill a column extending from 0% at the x-axis up to the value of the percentage at that bin.

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 typeIt 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, maxIt 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.