# LAB 11

## Objectives

• Random Numbers
• Distribution
• Fortran-generated Charts

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:

• 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 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)
```