Self-Assessment Quiz: Why Fortran Is Fast

Twenty questions to confirm you can explain, not just recite, why Fortran runs fast. Aim for 16 or more. Answers and a topic map are at the end — take the whole quiz first.


Question 1

Which gfortran optimization level first turns on automatic vectorization? - A. -O0 - B. -O1 - C. -O2 - D. -O3

Question 2

-Ofast differs from -O3 mainly because it adds -ffast-math, which: - A. Makes the compiler use more memory - B. Lets the compiler reorder floating-point arithmetic (treating it as associative), which can change results - C. Disables vectorization - D. Forces double precision everywhere

Question 3

"Inlining" is the optimization that: - A. Removes all loops from a program - B. Replaces a procedure call with a copy of the procedure's body in the caller - C. Converts a program to a single line - D. Stores arrays in the CPU registers permanently

Question 4

On typical hardware, a cache line is 64 bytes, which holds how many real(dp) values? - A. 1 - B. 4 - C. 8 - D. 64

Question 5

For a Fortran 2D array, the cache-friendly loop nest puts the inner loop over: - A. The last index - B. The first index - C. Either index — it makes no difference - D. The largest index

Question 6

A numerical loop described as "memory-bound" is one whose speed is limited primarily by: - A. How many floating-point operations it performs - B. How fast data can be moved between memory and the CPU - C. The number of variables declared - D. The length of the source file

Question 7

The "10× loop-order difference" quoted in this book should be understood as: - A. A guaranteed, exact factor on all hardware - B. An illustrative order of magnitude whose true value you measure yourself - C. A benchmark the authors ran and recorded - D. The speedup from adding more RAM

Question 8

The no-aliasing advantage refers to the fact that Fortran: - A. Never uses pointers - B. Forbids a procedure's written argument from overlapping a read argument, letting the compiler assume distinctness - C. Automatically parallelizes every loop - D. Stores arrays in row-major order

Question 9

C's restrict keyword exists in order to: - A. Make pointers read-only - B. Let the C programmer promise, per pointer, the non-aliasing that Fortran guarantees by default - C. Restrict which functions can be called - D. Force the compiler to use -O0

Question 10

Aliasing a written dummy argument with a read one in Fortran is: - A. A guaranteed compile-time error - B. Always safe - C. Undefined behavior — the programmer's responsibility to avoid - D. Automatically fixed by the compiler

Question 11

A pure procedure helps the optimizer because it promises to: - A. Run faster than other procedures - B. Have no side effects, so calls may be hoisted, shared, reordered, or removed - C. Use only integer arithmetic - D. Always be inlined

Question 12

An elemental procedure is one that: - A. Cannot be called on arrays - B. Is written for scalar arguments but may be applied elementwise to whole arrays, and is automatically pure - C. Is the fastest kind of subroutine by definition - D. Must be recursive

Question 13

The gfortran flag -fopt-info-vec-missed reports: - A. Every optimization the compiler applied - B. Loops that were not vectorized, with the reason - C. Memory leaks - D. Compile time per function

Question 14

On Compiler Explorer, an instruction named vaddpd (versus addsd) tells you the loop was: - A. Not compiled - B. Vectorized — "packed double" operates on several values at once - C. Running on the GPU - D. Written in assembly by hand

Question 15

Why can c = a + b (whole-array) be better information for the compiler than a hand-written element loop? - A. It uses less memory - B. It states the whole operation over known-shape, guaranteed-distinct arrays — exactly what vectorization needs - C. It is always run in parallel - D. It avoids floating-point arithmetic

Question 16

Does gfortran unroll your loops automatically at -O3? - A. Yes, always - B. No — you request unrolling explicitly with -funroll-loops (or via profile-guided optimization) - C. Only for integer loops - D. Only with -O0

Question 17

True or false: "Fortran is fast because it is a low-level language, close to the hardware like assembly."

Question 18

The Project Checkpoint compares the two loop orders' output with maxval(abs(fi - fj)) and gets exactly zero. This is legitimate (despite Chapter 20's warning about float equality) because: - A. Fortran rounds all differences to zero - B. The two orders perform identical arithmetic per element, so the results are bit-for-bit equal - C. maxval ignores small differences - D. The arrays are integers

Question 19

Which is the correct professional order of operations for making code fast? - A. Optimize first, then measure to confirm - B. Measure/profile to find the real bottleneck, then optimize it, then measure again - C. Rewrite in assembly immediately - D. Turn on -Ofast and stop thinking

Question 20

What does this print?

real(dp) :: x(4) = [1.0_dp, 2.0_dp, 3.0_dp, 4.0_dp], y(4) = [0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp]
call axpy(2.0_dp, x, y)      ! pure subroutine: y = y + alpha*x
print '(4f6.1)', y
  • A. 1.0 2.0 3.0 4.0
  • B. 2.0 4.0 6.0 8.0
  • C. 0.0 0.0 0.0 0.0
  • D. 3.0 6.0 9.0 12.0

Answer Key

Q Ans Why
1 D Auto-vectorization turns on at -O3.
2 B -ffast-math reorders FP arithmetic (assumes associativity) and can change results.
3 B Inlining pastes the callee's body into the caller, removing call overhead and enabling further optimization.
4 C 64 bytes / 8 bytes per real(dp) = 8 values.
5 B Fortran is column-major; the first index varies fastest, so it belongs innermost.
6 B Memory-bound = limited by memory traffic, not arithmetic.
7 B All timings here are illustrative orders of magnitude; you measure the real one.
8 B The standard forbids aliasing a written argument with a read one.
9 B restrict is C's opt-in promise of the non-aliasing Fortran guarantees by default.
10 C It is undefined behavior, not a diagnosed error; the programmer must avoid it.
11 B No side effects → the compiler may hoist, share, reorder, or delete calls.
12 B Scalar body, array-ready, automatically pure.
13 B It reports loops that failed to vectorize, with the reason.
14 B …pd = packed double = vectorized; …sd = scalar double.
15 B It exposes structure (shape, distinctness) the compiler needs to vectorize.
16 B gfortran unrolls only when asked (-funroll-loops) or under PGO.
17 False Fortran is high-level; its speed comes from letting the compiler optimize array code freely.
18 B Identical per-element arithmetic → bit-for-bit identical results, so the difference is exactly 0.
19 B Measure first, optimize the real bottleneck, then measure again (Chapter 28's ethic).
20 B y = 0 + 2*[1,2,3,4] = [2,4,6,8].

Topics to review by question

  • Q1–3, 16 → §27.1 (what the compiler does; optimization levels; inlining; unrolling).
  • Q4–7, 15 → §27.2 (cache line, memory-bound, column-major loop order, the illustrative 10×).
  • Q8–10, 17 → §27.3 (the no-aliasing advantage; restrict; undefined behavior).
  • Q11–12, 20 → §27.4 (pure/elemental as optimization licenses).
  • Q13–14 → §27.5 (reading the optimization report; packed vs scalar assembly).
  • Q18 → Project Checkpoint + Chapter 20 (bit-identical arithmetic).
  • Q19 → §27.5 and the bridge to Chapter 28 (measure first).

Scored below 16? The two sections to reread are §27.2 (loop order) and §27.3 (no aliasing) — they are the load-bearing ideas the rest of Part VII is built on.