Chapter 3 — Key Takeaways (Variables, Types, and Arithmetic)
A one-page reference. Types, kinds, the integer-division trap, and the arithmetic you will use in every program from here on.
The six intrinsic types
| Type | Holds | Example declaration | Notes |
|---|---|---|---|
integer |
whole numbers, exact | integer :: n = 42 |
default ≈ 32-bit, range ±2.1×10⁹ |
real |
floating-point, approximate | real(dp) :: t |
plain real is single (~7 digits) — avoid in numerics |
double precision |
~15-digit real (legacy keyword) | double precision :: x |
prefer real(dp); you'll read this in old code |
complex |
a pair $a + b\,i$ | complex :: z = (3.0, 4.0) |
real(z), aimag(z), abs(z)=modulus |
logical |
.true. / .false. |
logical :: ok = .true. |
prints as T/F under l1 |
character |
fixed-length text | character(len=5) :: s |
length is fixed (deferred-length → Ch. 12) |
Kinds and portable precision (the one habit that matters most)
integer, parameter :: dp = selected_real_kind(15, 307) ! ≥15 digits, range 10^307
real(dp) :: t ! declare reals like this
t = 0.5_dp ! literals get the _dp suffix
- Never hardcode a kind number (
real(8)): the number is compiler-specific. Request the requirement. selected_real_kind(p, r)→ real kind with ≥pdigits and range ≥10^r(negative if impossible).selected_int_kind(r)→ integer kind holding all values up tordecimal digits (e.g.(18)→ 64-bit).- Shortcut:
use, intrinsic :: iso_fortran_env, only: dp => real64(the 64-bit kind, by bit width). precision(x)→ decimal digits;range(x)→ decimal exponent range;kind(x)→ the raw kind number.
Arithmetic, precedence, and mixed-mode
- Operators:
**(exponentiation) →* /→+ -; parentheses override.**is right-associative:2**3**2 = 2**(3**2) = 512. - Mixed-mode: in each operation, the lower type is promoted before computing.
Ranking:
integer→real→double→complex.2 * 3.0→6.0(real). - The type of a subexpression is set by its operands, not by where the result is assigned.
The integer-division trap ⚠️ (the #1 beginner bug)
| Expression | Result | Why |
|---|---|---|
1 / 2 |
0 |
integer ÷ integer, truncates toward zero |
7 / 2 |
3 |
3.5 truncated |
-7 / 2 |
-3 |
truncates toward zero (not floor → not -4) |
real(dp) :: x; x = 1/2 |
0.0 |
1/2 computed as integer first, then widened |
real(1, dp) / real(2, dp) |
0.5 |
convert an operand before dividing |
1.0_dp / 2.0_dp |
0.5 |
real literals → real division |
Rule: for a real result, make sure at least one operand of every / is real (real(k, dp) or a _dp
literal). A real variable on the left never rescues integer division on the right.
mod vs modulo (differ only for negative arguments)
| Call | Result | Sign follows |
|---|---|---|
mod(7, 3) / modulo(7, 3) |
1 / 1 |
(agree when positive) |
mod(-7, 3) |
-1 |
the dividend (like C %, Python math.fmod) |
modulo(-7, 3) |
2 |
the divisor (like Python %) — use for periodic wraparound |
Intrinsic math functions
sqrt · abs · sin/cos/tan (radians!) · exp/log/log10 · ** · mod/modulo ·
max/min · real(x[,kind]) · aimag · int/nint/floor/ceiling · hypot.
Degrees → radians: r = deg * pi / 180.0_dp. An intrinsic function is built in — no import, no library.
Named constants — parameter
real(dp), parameter :: pi = 3.141592653589793_dp ! fixed at COMPILE time
real(dp), parameter :: two_pi = 2.0_dp * pi ! may derive from other parameters
Reassigning a parameter is a compile-time error (a feature). Zero run-time cost — the value is folded
into the code. Use it for dp, physical constants, and fixed sizes.
Formatted output (sketch — full story in Ch. 7)
| Descriptor | Prints | Example → output |
|---|---|---|
i0 / i4 |
integer (min width / width 4) | i4 of 7 → ␣␣␣7 |
f8.3 |
fixed-point, width 8, 3 decimals | 21.5 → ␣␣21.500 |
es12.4 |
scientific, mantissa in [1,10) | 1.0e-4 → ␣␣1.0000E-04 |
a |
character text as-is | — |
1x / / |
one space / new line | — |
A value too wide for its field prints as *s — a loud "widen me," not a silent truncation.
Numbers & rules worth memorizing
1/2 == 0— integer division truncates toward zero.dp = selected_real_kind(15, 307);real(dp)everywhere;_dpon every real literal.- Trig takes radians.
modfollows the dividend,modulothe divisor. - Default
real≈ 7 digits;real(dp)≈ 15 digits. Defaultintegermaxes near 2.1×10⁹.
🐍 Python contrasts (for the polyglot)
- Python
/is always real; Fortran integer/≈ Python//but truncates (Fortran-7/2 = -3, Python-7//2 = -4). - Python ints are arbitrary-precision; Fortran integers are fixed-width (overflow near ±2.1×10⁹ by default).
- Python floats are always 64-bit; Fortran default
realis 32-bit — which is why we insist onreal(dp).
Project piece added this chapter
kinds.f90 — a module kinds exporting integer, parameter :: dp = selected_real_kind(15, 307) — plus the
plate's physical constants (alpha, length, nx, dx) as real(dp)/integer parameters, with dx
derived safely via real(nx - 1, dp). This module is permanent; it reaches the Chapter 38 capstone unchanged.