Midterm Exam
Covers Parts I–II (Chapters 1–13): the foundations — types and kinds, control flow, arrays, procedures,
I/O — and the modern features — modules, derived types, object orientation, pointers, strings, and error
handling. A model solution set with every output hand-computed is in
midterm-solutions.md.
Instructions
- Closed book. No notes, no compiler, no internet. A blank sheet for scratch work is allowed.
- Time: approximately 2 hours.
- Total: 100 points, distributed as below. Point values are shown on every question; budget your time accordingly.
- All code is Modern Fortran (free-form,
gfortran -std=f2018 -Wall). Assumeimplicit noneis in force and that a real kinddpis defined asinteger, parameter :: dp = selected_real_kind(15, 307)(or imported asdp => real64) whereverreal(dp)appears. - For "what does this print?" questions, work the output out by hand exactly — including field widths and spacing — the way the book's own expected-output comments were written. No program here was run.
- For code you write, use modern style:
implicit none,real(dp)with_dpliterals, anintenton every dummy argument, assumed-shape array arguments, and aresultclause on functions. Warnings count against you the way they would in a graded problem set.
| Part | Topic | Points |
|---|---|---|
| A | Concepts (short answer) | 25 |
| B | Read the code (what does this print?) | 25 |
| C | Find the bug (diagnose + fix) | 20 |
| D | Write it | 30 |
| Total | 100 |
Part A — Concepts (25 points)
Answer in two to four sentences each. Precision counts: a vague-but-not-wrong answer earns partial credit, a confidently wrong claim earns none.
A1. (3 pts) The two Fortrans. People who say "Fortran" often mean two very different languages. Name the two eras, give one concrete distinguishing feature of each, and say which one this book teaches.
A2. (4 pts) Why Fortran is fast. The book attributes Fortran's speed on numerical code to two design decisions made very early. Name both and, in one sentence each, explain why each one lets the compiler produce faster machine code than it otherwise could.
A3. (3 pts) implicit none. What does implicit none do, and what specific class of bug does it turn
from a silent run-time error into a compile-time error? Illustrate with a one-word example.
A4. (3 pts) Kinds and dp. Why does this book write integer, parameter :: dp = selected_real_kind(15,
307) and then real(dp) everywhere, rather than plain real or real(8)? What do the two arguments
15 and 307 request, and what must you write on a real literal so it has the right kind?
A5. (3 pts) Column-major order. State what "column-major" means for the memory layout of a 2-D Fortran array, and give the practical rule it implies for the order of a nested loop that sweeps the array. What roughly is the penalty for getting the loop order backwards?
A6. (3 pts) Modules vs. COMMON. A FORTRAN 77 program shares global state through a COMMON block; a
modern program uses a module. Give one concrete reason the module is safer — something the compiler can do
for the module that it cannot do for COMMON.
A7. (3 pts) intent. List the three intents and what each one promises. Then state the one thing the
compiler does with an intent(in) declaration that makes it "a free bug-catcher."
A8. (3 pts) allocatable vs. pointer. State the book's default rule for choosing between an
allocatable array/component and a pointer, give two reasons for the default, and name one situation
in which a pointer is genuinely the right tool.
Part B — Read the Code (25 points)
Each snippet is a complete, warning-free program. Write down exactly what it prints, one line per output line, getting the spacing and field widths right. (5 points each.)
B1. (5 pts) Arithmetic and division.
program b1
use, intrinsic :: iso_fortran_env, only: dp => real64
implicit none
integer :: a = 7, b = 2
real(dp) :: x
x = a / b
print '(a, f6.3)', 'x1 = ', x
x = real(a, dp) / b
print '(a, f6.3)', 'x2 = ', x
print '(a, i0)', 'p = ', a / b + 1
print '(a, i0)', 'm = ', mod(a, b)
print '(a, i0)', 'q = ', modulo(-7, 3)
end program b1
B2. (5 pts) Arrays, sections, and whole-array reductions. Remember how Fortran streams a rank-2 array.
program b2
implicit none
integer :: a(2, 3), i, j
do j = 1, 3
do i = 1, 2
a(i, j) = 10*i + j
end do
end do
print '(a, 6i4)', 'flat = ', a
print '(a, 2i4)', 'col2 = ', a(:, 2)
print '(a, i0)', 'total= ', sum(a)
print '(a, i0)', 'big = ', count(a > 25)
end program b2
B3. (5 pts) select case.
program b3
implicit none
integer :: n(4) = [3, 0, -5, 12]
integer :: k
character(len=8) :: label
do k = 1, 4
select case (n(k))
case (:-1)
label = 'negative'
case (0)
label = 'zero'
case (1:9)
label = 'small'
case default
label = 'large'
end select
print '(i4, a, a)', n(k), ' -> ', trim(label)
end do
end program b3
B4. (5 pts) A procedure with intent.
program b4
use, intrinsic :: iso_fortran_env, only: dp => real64
implicit none
real(dp) :: x(4) = [1.0_dp, 2.0_dp, 3.0_dp, 4.0_dp]
call accumulate(x, 10.0_dp)
print '(a, 4f6.1)', 'x = ', x
print '(a, f6.1)', 'sum = ', array_sum(x)
contains
subroutine accumulate(v, offset)
real(dp), intent(inout) :: v(:)
real(dp), intent(in) :: offset
v = v + offset
end subroutine accumulate
pure function array_sum(v) result(s)
real(dp), intent(in) :: v(:)
real(dp) :: s
s = sum(v)
end function array_sum
end program b4
B5. (5 pts) A derived type and whole-object assignment.
program b5
use, intrinsic :: iso_fortran_env, only: dp => real64
implicit none
type :: box
real(dp) :: w, h, d
end type box
type(box) :: a, b
a = box(2.0_dp, 3.0_dp, 4.0_dp)
b = a
b%h = 10.0_dp
print '(a, f6.1)', 'a vol = ', a%w * a%h * a%d
print '(a, f6.1)', 'b vol = ', b%w * b%h * b%d
print '(a, f6.1)', 'a h = ', a%h
end program b5
Part C — Find the Bug (20 points)
Each fragment is intended to do the job in its comment but is wrong. For each, (i) diagnose the defect — say what is wrong and why — and (ii) fix it, writing the corrected line(s). A fix with no explanation earns at most half credit.
C1. (7 pts) Intended: compute the mean of the four scores as a real number.
real(dp) :: mean
integer :: scores(4) = [90, 85, 82, 96]
mean = sum(scores) / 4
print '(a, f6.2)', 'mean = ', mean
The program prints mean = 88.00, but the true mean is not 88.00. What went wrong, and what is the fix?
C2. (7 pts) Intended (written by a programmer with a C habit): fill a 5-element array so that
v(k) = k*k.
integer :: v(5), k
do k = 0, 4
v(k) = k * k
end do
print '(5i5)', v
This is wrong in two related ways. Identify both and give the corrected loop.
C3. (6 pts) Intended: add the elements of x into the running total acc (the caller passes in a total
so far and expects it increased).
subroutine add_into(acc, x)
real(dp), intent(out) :: acc
real(dp), intent(in) :: x(:)
acc = acc + sum(x)
end subroutine add_into
The "running total" comes out as garbage — the caller's incoming value is lost. Why, and what is the one-word fix?
Part D — Write It (30 points)
Write complete, compilable, modern-style Fortran. Include implicit none, an intent on every dummy
argument, real(dp) with _dp literals, and a result clause on each function.
D1. (10 pts) A pure function. Write a pure function
rms(v)
that takes a rank-1 real(dp) array v as an assumed-shape argument and returns its root-mean-square,
$\sqrt{\frac{1}{n}\sum_i v_i^2}$, where $n$ is the number of elements. Use whole-array operations and array
intrinsics — no explicit loop. Show it inside a short program that calls it once and prints the result, and
state the printed value for v = [3.0_dp, 4.0_dp, 0.0_dp, 0.0_dp].
D2. (12 pts) A module with a derived type and a type-bound procedure. Write a module geometry that
defines a derived type rectangle with two real(dp) components (width, height, each defaulting to
zero) and a type-bound procedure area that returns width * height. Make the module "private by
default, public on purpose" so that only the type name is exported. Then write a short driver program that
uses the module, constructs a rectangle with width 3.0 and height 4.0, and prints its area by calling
the method as r%area(). Get the passed-object dummy argument's declaration exactly right.
D3. (8 pts) A small array computation. Write a complete program that, given the array
real(dp) :: t(6) = [1.0_dp, 5.0_dp, 3.0_dp, 9.0_dp, 2.0_dp, 4.0_dp], computes (a) the mean of t and
(b) the number of elements of t that are strictly greater than the mean — using array intrinsics and a
whole-array comparison as a mask, with no explicit loop. Print both results, and state the two printed
values.
End of exam. Check that you answered every part; unanswered questions earn zero, partially-correct answers earn partial credit.