; Fieldtest — Floats milestone, axis 3: NaN / Inf / is_nan handling. ; ; safe_div(a, b) returns a/b when b != 0; falls through to the IEEE ; result otherwise. The fixture exercises four cases: ; 1) 6.0 / 3.0 -> 2.0 (normal) ; 2) 1.0 / 0.0 -> +inf (use is_nan to confirm finite-vs-NaN) ; 3) 0.0 / 0.0 -> NaN (is_nan should report true) ; 4) (- 1.0 1.0) / 0.0 -> NaN (subexpr drives same) ; ; classify(x) returns: ; -1 if x is NaN ; 0 if x is +inf or -inf (we test via x > / x < -) ; 1 otherwise ; ; The subtle point: the IEEE-correct way to test for NaN is `is_nan`, ; NOT `(== x x)` (which is false for NaN — but the LLM author who ; reaches for `==` first will get the right answer by accident here, ; only because the natural reading of the operator doesn't apply). ; design/contracts/float-semantics.md says explicitly to use `is_nan`. ; ; Expected stdout (one per line): ; 2.0 ; 6/3 ; 1 ; classify(2.0) -> normal ; inf ; 1/0 ; 0 ; classify(1/0) -> infinite ; nan ; 0/0 ; -1 ; classify(0/0) -> NaN ; ; (`print` for Float routes through `float_to_str`, which uses "%g", so inf prints as "inf", NaN as "nan".) (module floats_3_safe_division (fn classify (doc "-1=NaN, 0=infinite, 1=finite. Uses is_nan + abs > huge.") (type (fn-type (params (con Float)) (ret (con Int)))) (params x) (body (if (app is_nan x) -1 (if (app > x 1.0e308) 0 (if (app < x -1.0e308) 0 1))))) (fn main (type (fn-type (params) (ret (con Unit)) (effects IO))) (params) (body (seq (app print (app / 6.0 3.0)) (seq (app print (app classify (app / 6.0 3.0))) (seq (app print (app / 1.0 0.0)) (seq (app print (app classify (app / 1.0 0.0))) (seq (app print (app / 0.0 0.0)) (app print (app classify (app / 0.0 0.0)))))))))))