Chapter 3 — Teaching Notes

One-line purpose. Give students exact command of how Fortran represents numbers (types + kinds) and computes with them (mixed-mode + the integer-division trap), and establish the real(dp) house style and the project's kinds module — the numerical bedrock every later chapter stands on.

Key ideas to emphasize

  • The integer-division trap is the chapter's center of gravity. 1/2 == 0 is not a curiosity; it is the single most common wrong-answer bug students will ship, and the compiler cannot warn about it. Drill the mental model: the type of a subexpression is decided by its operands, before the result is assigned. A real on the left never rescues integer division on the right.
  • Precision is a decision, not a default. Plain real is single precision (~7 digits). Make students physically uncomfortable writing bare real for a physical quantity. dp = selected_real_kind(15, 307), real(dp), _dp literals — this is house style from now to Chapter 38.
  • Request the requirement, not the representation. selected_real_kind(15, 307) states "I need 15 digits"; real(8) hardcodes a compiler-specific number. The kind-number output (8 on gfortran) is a teaching moment against hardcoding, not a fact to memorize.
  • mod vs modulo. They agree for positive arguments and split on the sign for negatives. Students only hit this at boundaries (periodic domains), which is exactly where simulations break — so plant it now.

Misconceptions to preempt

  • "The variable is real, so the division is real." (No — operand types decide; assignment is too late.)
  • "A decimal point in the output means real arithmetic happened." (No — f8.3 prints any real, including one widened from an integer quotient at the last moment. See CS-01.)
  • "real(8) is the way to get double precision." (Compiler-specific; use selected_real_kind.)
  • "Double precision is slower, so single is a downgrade." (Single is often faster — memory-bound codes move half the bytes; the trade-off is accuracy, not speed. Don't let "double = better" go unchallenged.)
  • "Trig takes degrees." (Radians. sin(30.0_dp) is a classic silent bug.)
  • "9.81 and 9.81_dp are the same." (The first is a single-precision literal, rounded before it is widened.)

A live demonstration (5–8 minutes)

Type the temperature-conversion bug live: c = 5 / 9 * (f - 32.0_dp). Compile with -Wall — no warnings — and run: every temperature comes out 0.0. Ask the class why before revealing it. Then fix only the fraction (5.0_dp / 9.0_dp) and rerun to 37.0. In under ten minutes students see (a) that clean-compiling code can be dead wrong, (b) that -Wall cannot catch it, and (c) the exact fix. Follow with the kinds_demo program to show precision(1.0) = 6 vs precision(1.0_dp) = 15 on the projector — the whole case for dp in two numbers.

Class-time budget (~50 min)

  • 8 min: the six types; declaration; implicit none still watching (§3.1).
  • 12 min: kinds, selected_real_kind, dp, single-vs-double precision (§3.2) — the live kinds_demo.
  • 15 min: mixed-mode + the integer-division trap (§3.3–3.4) — the live conversion bug; mod vs modulo.
  • 8 min: math intrinsics (radians!) and parameter (§3.5–3.6).
  • 7 min: formatted output sketch (§3.7) and launch the kinds.f90 project increment.

Prerequisites to review

Chapter 2: implicit none, the compile command (gfortran -std=f2018 -Wall), and the compile–link–run cycle. Confirm every student can compile and run a one-line program before class — the exercises are almost all "type, compile, and run," and an unresolved install blocks the whole session.

Connections

Back: Ch. 1 (heat-solver origin; "performance is not accidental"), Ch. 2 (implicit none, flags). Forward: Ch. 4 (the time loop that consumes these constants), Ch. 5 (types become array types), Ch. 6 (intent), Ch. 7 (edit descriptors in full), Ch. 8 (modules — kinds grows up), Ch. 20 (why floating point is approximate — the depth deferred here), Ch. 24 (the stability condition behind dt_max). Naming these payoffs keeps the dp discipline from feeling like arbitrary ceremony.