Fixed Stars Need Fixed Points
Picture this: you’re calibrating a sextant against Polaris, measuring its apparent drift over hours of long exposure. Your calculations need to be precise to the arc-second, because a tiny error in stellar position translates to kilometres of navigational mistake. This is exactly the problem that drove NASA’s Apollo Guidance Computer to abandon floating-point arithmetic entirely.
The issue isn’t just precision—it’s predictable precision. Floating-point numbers get less accurate as they grow larger, but celestial navigation demands consistent accuracy across vastly different scales, from microsecond timing corrections to multi-million-kilometre orbital mechanics.
;; Clojure's rationals give exact arithmetic
(defn star-drift [initial-pos drift-rate hours]
(+ initial-pos (* drift-rate hours)))
;; 0.158 arc-seconds per hour over 8.5 hours
(println (star-drift 127/4 79/500 17/2))
;; => 33093/1000 (exact: 33.093 arc-seconds)
Clojure sidesteps the whole mess with rational numbers—fractions that never lose precision. That 33093/1000 isn’t an approximation; it’s mathematically exact.
Ada takes a different approach, baking fixed-point types directly into the language:
type Arc_Seconds is delta 0.001 range -3600.0 .. 3600.0;
Initial_Pos : Arc_Seconds := 31.750;
Drift_Rate : Arc_Seconds := 0.158;
Final_Pos := Initial_Pos + Drift_Rate * 8.5;
-- Result: 33.093 (guaranteed precision)
Ada’s delta keyword defines the smallest representable difference—here, one thousandth of an arc-second. The compiler ensures all arithmetic maintains this precision, making overflow and underflow predictable rather than mysterious.
Both approaches solve the same problem that plagued early navigation computers: when you’re betting lives on mathematics, “close enough” isn’t close enough. Fixed-point arithmetic trades the flexibility of floating-point for something more valuable—absolute certainty about where your decimal places are.