C      Programmer: Charles (Chase) Ganey
C      Course: CS430
C      Date Due: September 12, 2007
C      Language: Fortran
C      Compiler used: FORCE2.08
C      Source Filename: PA2_Chase_Ganey.f
C      Executable Filename (if any) or None: PA2_Chase_Ganey.EXE
C      Professor: Elizabeth Adams
C      Purpose:  This program converts an integer number (between 1 and
C      32767 inclusive) in base 10 to base 2.  It also converts a
C      decimal number between 0 and 1 (exclusive) in base 10 to base 2.

C      Input:  An integer between 1 and 32767 (inclusive) for the first
C      prompt.  The second prompt asked for a decimal between 0 and 1.
C      NOTE: The second prompt must include the decimal point for proper
C      error checking and results.

C      Output:   The output for the first prompt echos the integer
C      in base 10 then outputs its equivalent in base 2.  The second
C      prompt echos the decimal in base 10 and then outputs its
C      equivalent in base 2.

C      Language  Information: All the variable names in the program that
C      begin with letter I are integers.  All other variables are
C      REAL because their first letter don't begin with I-N.

C      ICOUNT is used to prevent writing garbage (elements in the
C      array that were not used.

C      DIMENSION indicates that the variable name(s) which follow are arrays

C      The number in parentheses indicates the size of the array

C      If the array is to be an integer array its name must begin with one of the letters I-N

C      Although the values to be read are real values, the format statement places the decimal points

C      READ is the input statement.

C      = is the assignment operator

C      **  is the exponentiation operator

C      .GT. is a greater than conditional operator

C      .LT. is a less than conditional operator

C      .GE. is a greater than or equal to operator

C      .LE. is a less than or equal to operator

C      WRITE is the output statement

C      6 in WRITE (6,_) is the default output device
C      the numbers after  6,  in the WRITE statements are the labels for
C      the related FORMAT statements

C      FORMAT statements are not executable and may be placed anywhere
C      in the program

C      All WRITE statements should have a 1X as the first element in
C      the format list

C      One way of putting labels on printed output is to put the label
C      as a string in the FORMAT statement

C      The F format indicates a real number is to be output.

C      The number before the I indicates the number of integers that
C      the program should expect

C      The number after the I in the FORMAT statement indicates the
C      width of the integer

C      The 1st number after the F in the FORMAT statement indicates
C      the total number of digits the number is

C      NOTE: In read FORMAT statements, FORTRAN doesn't count the
C      decimal point as a place.  But in the write FORMAT statements,
C      it does count the decimal point as a place (that's why in this
C      program it's F7.6 instead of its read F6.6)

C      The 2nd number after the F in the FORMAT statement indicates
C      numer of places after the decimal point

C      In SUBROUTINE ICONVERSION2, it uses the INT() function.
C      This function simply truncates a REAL number into an
C      integer.

C      The STOP statement ends the program execution

C      The END statement marks the end of a compilation unit

        DIMENSION ICONVERSION(15)
        DIMENSION ICONVERSION2(6)
        
C       Maximum possible size for base 2 array for base 10 integer
C       conversion.
        IDIM = 15

C       Maximum possible size for base 2 array for base 10 decimal
C       conversion.
        IDIM2 = 6
        
C       Tell the user to enter an integer in the range of 1 to 32767.
C       ERROR CATCHING NOTE: If an invalid number is entered (e.g. a
C       REAL number or a negative number) then it will GOTO statement
C       30.
9       WRITE(6,10)
10      FORMAT(1X, 'Please enter an integer in the range of 1 to 32767')
        READ(5,11,ERR = 30) INUMBER
11      FORMAT(I5)

C       Make sure entered integer is within the specified range.
C       ERROR CATCHING NOTE: This is a second error check because the
C       previous check doesn't pick up numbers outside of the range.
        IF (INUMBER .LT. 1 .OR. INUMBER .GT. 32767) GOTO 28
        
C       Echo the integer with a maximum of 5 places
        WRITE(6,12) INUMBER
12      FORMAT(1X, 'The base 10 value of the input is: ', I5)

C       Convert the base 10 integer to base 2
        CALL CONVERTI(INUMBER, ICONVERSION, IDIM, ICOUNT)

C       Write the base 2 conversion by iterating through ICONVERSION
C       in REVERSE order (the CONVERTI subroutine stores the base 2
C       conversion in reverse order)
        WRITE (6,13) (ICONVERSION(I), I = ICOUNT,1,-1)
13      FORMAT(1X, 'The base 2 value of the input is: ', 15I1)

C       Tell the user to enter a decimal between 0 and 1.
40      WRITE(6,14)
14      FORMAT(/1X, 'Please enter a number between 0 and 1.')
        WRITE(6,49)
49      FORMAT(1X, 'NOTE: Be sure to include the decimal point')
        WRITE(6,48)
48      FORMAT(1X, 'or your conversion will be incorrect!')
        READ(5,15) DECIMAL

C       Read in 6 numbers, all 6 are to the right of the decimal place
C       NOTE: Even if user doesn't include decimal point, it is
C       automatically inserted before the numbers.
15      FORMAT(F6.6)

C       Make sure entered decimal is within specified range.
C       ERROR CATCHING NOTE: This check will only catch any negative
C       numbers and any decimal numbers entered that have a decimal
C       point(e.g. -.435, 1.0).

C       It does not, however, catch input that does not have a decimal
C       point yet is still bigger than 1 (e.g. 2, 235235235).
C       Even if user doesn't include the decimal point, FORTRAN assumes
C       it is still there (e.g. 2 is assumed .000002) because it was read in
C       with FORMAT(F6.6) meaning all numbers are after the decimal
C       point (even if user did not include one).
        IF (DECIMAL .GE. 1 .OR. DECIMAL .LE. 0) GOTO 31

C       Echo the decimal with a maximum of 6 places after the decimal
C       point.
        WRITE(6,16) DECIMAL
16      FORMAT(1X, 'The base 10 value of the input is: ', F7.6)

C       Convert the base 10 decimal to base 2
        CALL CONVERTD(DECIMAL, ICONVERSION2, IDIM2, ICOUNT)

C       Write the base 2 conversion by iterating through ICONVERSION2
C       until the last element used (ICOUNT)
        WRITE (6,17) (ICONVERSION2(I), I = 1, ICOUNT)
17      FORMAT(1X, 'The base 2 value of the input is: .', 6I1)

C       Go to end of program
        GOTO 50

C       Error checking for valid range
28      WRITE(6, 29)
29      FORMAT (1X, 'Integer must be in range of 1 to 32767')
        GOTO 9

C       Error checking for valid number (must be integer)
30      WRITE (6, 20)
20      FORMAT (1X, 'HAD AN ERROR IN THE INPUT DATA')
        GOTO 9

C       Error checking for valid number (must be integer)
31      WRITE (6, 21)
21      FORMAT (1X, 'Decimal must be in range of 0 to 1')
        GOTO 40

C       Error checking for valid number (must be integer)
50      WRITE (6, 51)
51      FORMAT (/1X, 'Program ended successfully.')

        STOP
        END
        
C       SUBROUTINE CONVERTI - Converts integer base 10 to base 2.
C       PARAMETERS:
C       INUMBER is the base 10 integer number.
C       ICONVERSION is the integer array that will hold the base 2
C                   conversion.
C       IDIM is the dimension of the array (15).
C       ICOUNT keeps track of how many elements of the array are used.
        SUBROUTINE CONVERTI(INUMBER, ICONVERSION, IDIM, ICOUNT)

C       Declare array with dimension of 15 elements
        DIMENSION ICONVERSION(IDIM)

C       Initialize counter to 0
        ICOUNT = 0

C       Loop from 1 to 15 (maximum length of binary base 2 output)
        DO 20 I = 1, IDIM

C       Must check if INUMBER is 0 to terminate loop.  If so, no more
C       iterations of the loop are required.
        IF (INUMBER .EQ. 0) GOTO 21

C       Store the remainder from INUMBER/2 into IREM
        IREM = MOD(INUMBER, 2)

C       This remainder is stored in the Ith place of the array
        ICONVERSION(I) = IREM

C       Divide INUMBER by 2 to continue finding all the base 2 places
        INUMBER = INUMBER / 2

C       Keep count of how many elements are used in the ICONVERSION
C       array.
        ICOUNT = ICOUNT + 1
20      CONTINUE
21      RETURN
        END
        
C       SUBROUTINE CONVERTD - Converts decimal base 10 to decimal base
C       2.
C       PARAMETERS:
C       DECIMAL is the base 10 decimal number.
C       ICONVERSION2 is the integer array that will hold the base 2
C                    conversion.
C       IDIM2 is the dimension of the array (6).
C       ICOUNT keeps track of how many elements of the array are used
        SUBROUTINE CONVERTD(DECIMAL, ICONVERSION2, IDIM2, ICOUNT)

C       Declare array with dimension of 6 elements
        DIMENSION ICONVERSION2(IDIM2)

C       Reset ICOUNT back to 0 (was already used in subroutine CONVERTI)
        ICOUNT = 0

C       Loop from 1 to 6 (maximum length of decimal base 2 output
        DO 20 I = 1, IDIM2

C       Must check if DECIMAL reached 0.0 to terminate loop.  If it
C       reaches 0.0 then no more iterations are required.
        IF (DECIMAL .EQ. 0.0) GOTO 21

C       Multiply DECIMAL by 2 to determine the the base 2 value in its
C       result one place to the left of the decimal point (ONE's place).
        DECIMAL = DECIMAL * 2

C       Extract the base 2 value by truncating the the integer from
C       the floating point decimal (will always be 0 or 1)
        ICONVERSION2(I) = INT(DECIMAL)

C       Check if DECIMAL is greater than or equal to 1.  If so, subtract
C       the 1 to leave you with just the decimal places.
        IF (DECIMAL .GE. 1) DECIMAL = DECIMAL - 1

C       Keep count of how many elements are used in the ICONVERSION2
C       array
        ICOUNT = ICOUNT + 1
20      CONTINUE
21      RETURN
        END


