16.6: Example Two
- Page ID
- 54371
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\( \newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\)
( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\id}{\mathrm{id}}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\kernel}{\mathrm{null}\,}\)
\( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\)
\( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\)
\( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\AA}{\unicode[.8,0]{x212B}}\)
\( \newcommand{\vectorA}[1]{\vec{#1}} % arrow\)
\( \newcommand{\vectorAt}[1]{\vec{\text{#1}}} % arrow\)
\( \newcommand{\vectorB}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vectorC}[1]{\textbf{#1}} \)
\( \newcommand{\vectorD}[1]{\overrightarrow{#1}} \)
\( \newcommand{\vectorDt}[1]{\overrightarrow{\text{#1}}} \)
\( \newcommand{\vectE}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash{\mathbf {#1}}}} \)
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\(\newcommand{\avec}{\mathbf a}\) \(\newcommand{\bvec}{\mathbf b}\) \(\newcommand{\cvec}{\mathbf c}\) \(\newcommand{\dvec}{\mathbf d}\) \(\newcommand{\dtil}{\widetilde{\mathbf d}}\) \(\newcommand{\evec}{\mathbf e}\) \(\newcommand{\fvec}{\mathbf f}\) \(\newcommand{\nvec}{\mathbf n}\) \(\newcommand{\pvec}{\mathbf p}\) \(\newcommand{\qvec}{\mathbf q}\) \(\newcommand{\svec}{\mathbf s}\) \(\newcommand{\tvec}{\mathbf t}\) \(\newcommand{\uvec}{\mathbf u}\) \(\newcommand{\vvec}{\mathbf v}\) \(\newcommand{\wvec}{\mathbf w}\) \(\newcommand{\xvec}{\mathbf x}\) \(\newcommand{\yvec}{\mathbf y}\) \(\newcommand{\zvec}{\mathbf z}\) \(\newcommand{\rvec}{\mathbf r}\) \(\newcommand{\mvec}{\mathbf m}\) \(\newcommand{\zerovec}{\mathbf 0}\) \(\newcommand{\onevec}{\mathbf 1}\) \(\newcommand{\real}{\mathbb R}\) \(\newcommand{\twovec}[2]{\left[\begin{array}{r}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\ctwovec}[2]{\left[\begin{array}{c}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\threevec}[3]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\cthreevec}[3]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\fourvec}[4]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\cfourvec}[4]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\fivevec}[5]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\cfivevec}[5]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\mattwo}[4]{\left[\begin{array}{rr}#1 \amp #2 \\ #3 \amp #4 \\ \end{array}\right]}\) \(\newcommand{\laspan}[1]{\text{Span}\{#1\}}\) \(\newcommand{\bcal}{\cal B}\) \(\newcommand{\ccal}{\cal C}\) \(\newcommand{\scal}{\cal S}\) \(\newcommand{\wcal}{\cal W}\) \(\newcommand{\ecal}{\cal E}\) \(\newcommand{\coords}[2]{\left\{#1\right\}_{#2}}\) \(\newcommand{\gray}[1]{\color{gray}{#1}}\) \(\newcommand{\lgray}[1]{\color{lightgray}{#1}}\) \(\newcommand{\rank}{\operatorname{rank}}\) \(\newcommand{\row}{\text{Row}}\) \(\newcommand{\col}{\text{Col}}\) \(\renewcommand{\row}{\text{Row}}\) \(\newcommand{\nul}{\text{Nul}}\) \(\newcommand{\var}{\text{Var}}\) \(\newcommand{\corr}{\text{corr}}\) \(\newcommand{\len}[1]{\left|#1\right|}\) \(\newcommand{\bbar}{\overline{\bvec}}\) \(\newcommand{\bhat}{\widehat{\bvec}}\) \(\newcommand{\bperp}{\bvec^\perp}\) \(\newcommand{\xhat}{\widehat{\xvec}}\) \(\newcommand{\vhat}{\widehat{\vvec}}\) \(\newcommand{\uhat}{\widehat{\uvec}}\) \(\newcommand{\what}{\widehat{\wvec}}\) \(\newcommand{\Sighat}{\widehat{\Sigma}}\) \(\newcommand{\lt}{<}\) \(\newcommand{\gt}{>}\) \(\newcommand{\amp}{&}\) \(\definecolor{fillinmathshade}{gray}{0.9}\)In this example, we will write a simple program to perform some processing for students. The student information will be stored in an array of derived data types. There will be no more than 50 students per class. The main will call a subroutine to read student information (name and score) and another subroutine to set the student grades. Finally, the main will call a function to calculate the class average. The main will display the average. Routines for displaying the students are left as an exercise.
Understand the Problem
The main is expected to define the appropriate derived data type for student, declare some variables of that type and call the subroutines. The first subroutine will read student information, including a name (up to 60 characters) and score from the user. Names and scores should continue to be read until a blank name is entered. The score value must be between 0.0 and 100.0 (inclusive). For this simple example, we will re-prompt for incorrect data entry (until correct data is provided). The routine must return the count of students entered. The second subroutine sets the grades based on the following standard scale.
A | B | C | D | F |
---|---|---|---|---|
\(\geq 90\) | \(80 - 89\) | \(70 - 79\) | \(60 - 69\) | \(\leq 59\) |
When determining the final grade, the program should round up when appropriate. The main will call a function to calculate and return the average of the scores. Additionally, the main will display the final average.
Create the Algorithm
For this example main, part for the main includes a declaration, display header, call read time subroutine, and the call the time summation subroutine. The basic steps for the main include:
! define derived data type for student ! must include → name, id, grade ! declare variables ! includes → array for up to 50 students ! display initial header ! call subroutine to read student information ! call subroutine to set grades ! use function to calculate average of scores ! display average
The basic steps for the read student information subroutine include:
! subroutine header and appropriate declarations ! loop ! prompt for student name ! read name ! if name is empty, exit loop ! loop ! prompt for student score ! read score ! check score entered ! if [score is between 0.0 and 100.0, inclusive] exit ! display error message ! end loop ! update count of students ! place values in student array ! end loop
The basic steps for the set grades subroutine include:
! subroutine header and appropriate declarations ! loop ! read score / set grade ! ≥ 90 → A; 80 - 89 → B; 70 – 79 → C; 60 - 69 → D; ≤ 59 → F ! end loop
When determining the final grade, the nearest integer intrinsic function, nint()
, can be used to perform the appropriate rounding.
The basic steps for the calculate average score function include:
! function header and appropriate declarations ! loop ! sum scores ! end loop ! calculate and return average
For convenience, the steps are written as program comments.
Implement the Program
Based on the algorithm, the below program could be created.
program classScores ! define data type for student, includes → name, id, grade implicit none type student character(60) :: name real :: score character(1) :: grade end type ! declare variables, including → array for up to 50 students type(student), dimension(50) :: class integer :: count real :: average ! display initial header write (*,'(/,a,/)') "Student Information Example Program." ! call subroutine to read student information call readStudents (class, count) ! call subroutine to set grades call setStudentGrades (class, count) ! use function to calculate average of scores average = classAverage (class, count) ! display average write (*,'(/,a, f5.1)') "Final Class Average: ", average contains ! ******************************************************* ! Subroutine to read student information (name and score). ! A blank name will stop input ! The score must be between 0.0 and 100.0 (inclusive) subroutine readStudents (class, count) type(student), dimension(50), intent(out) :: class integer, intent(out) :: count = 0 character(60) :: tempname real :: tempscore do ! prompt for student name and read name write (*,'(a)',advance="no") "Enter Student Name: " read (*,'(a60)') tempname ! if name is empty, exit loop if ( len_trim(tempname) == 0 ) exit do ! prompt for student score and read score write (*,'(a)',advance="no") & "Enter Student Score: " read (*,*) tempscore ! check score entered if ( tempscore >= 0.0 .and. & tempscore <= 100.0 ) exit ! display error message write (*,'(a,/,a)') & "Error, invalid score.", & "Please re-enter time." end do ! update count of students and place in student array count = count + 1 class(count)%name = tempname class(count)%score = tempscore end do return end subroutine readStudents ! ******************************************************* ! Subroutine to set student grades. ! ≥90→A;80-89→B;70–79→C;60-69→D;≤59→F subroutine setStudentGrades (class, count) type(student), dimension(50), intent(inout) :: class integer, intent(in) :: count integer :: i ! check each score / set each grade do i = 1, count select case ( nint(class(i)%score) ) case (90:) class(i)%grade = "A" case (80:89) class(i)%grade = "B" case (70:79) class(i)%grade = "C" case (60:69) class(i)%grade = "D" case (:59) class(i)%grade = "F" end select end do return end subroutine setStudentGrades ! ******************************************************* ! Function to calculate average score. real function classAverage (class, count) type(student), dimension(50), intent(in) :: class integer, intent(in) :: count integer :: i real :: sum = 0.0 ! sum scores do i = 1, count sum = sum + class(i)%score end do ! calculate and return average classaverage = sum / real(count) return end function classAverage end program classScores
If the program does not work at first, the comments can aid in determining the problem.
Test/Debug the Program
For this problem, the testing would involve executing the program and entering a series of student data values to ensure that the results are correct. If the program does not provide the correct results, each of the subroutines and the function results should be verified individually. Each can be checked by displaying the intermediate results to the screen. In this manner, the subroutine or function that is not working correctly can be quickly identified. Once identified, some additional write statements inside the subprogram can be used to help identify the specific problem. The testing and debugging process is left to the reader as an exercise.