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). Assume implicit none is in force and that a real kind dp is defined as integer, parameter :: dp = selected_real_kind(15, 307) (or imported as dp => real64) wherever real(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 _dp literals, an intent on every dummy argument, assumed-shape array arguments, and a result clause 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.