flan/test/programs/math3.flan
Joseph Ferano a4c6b996ff def re-runs its initialiser, and defvar is renamed defonce
The trio the author decided on 2026-09-20 is now all built: def is CL's
defparameter — its initialiser runs on every daemon re-run, unguarded, so
an edited initialiser repaints the same storage on C-c C-c plus re-run —
defonce (Clojure's name for CL's defvar, per the author) initialises once
behind the .init~once. flag, and defconst stays the image.

One parse arm reads both forms; the difference is Ast.reinit, carried to
Tast.global's grerun. Emit.startup_plan gives a def no guard flag, and
Check.check_global lifts every def initialiser — zero and literal
included — into global/<n>, so the host's startup reaches it through the
function cell and a re-evaluated def swaps it (Session's def_inits;
Emit.redefinition declares the cell for a non-sibling target). The old
defvar spelling is refused with the rename and both compiling spellings,
and every program, test, doc and editor list is swept — except sand.flan,
the author's live WIP, whose seven defvar lines are flagged in FIX.org
and keep its three dependent tests red on this branch.
2026-09-21 07:12:04 +07:00

137 lines
5.8 KiB
Plaintext

;;;; The rest of libm, at both widths — what math.flan and math2.flan left out.
;;;;
;;;; The rule those two set holds here unchanged and is the only reason this
;;;; file looks the way it does: none of these is correctly rounded under
;;;; IEEE-754 except sqrt, fabs, the rounding three and fmod, so every value
;;;; below is one whose answer is exact in binary — zero, one, a power of two,
;;;; a perfect square, a perfect cube. A case that pinned glibc's last bit
;;;; would pass here and fail on wasi-libc.
;;;;
;;;; The acceptance table builds this at -O0 as well, and that run is the one
;;;; that matters: at -O2 LLVM folds a libm call over two literals and leaves
;;;; no symbol to resolve, which is how a missing -lm hid the first time.
(defn show [x f32] ()
(print x)
(print " "))
(defn show64 [x f64] ()
(print x)
(print " "))
;;; The operands of the (% ...) block at the end. See the note there for why
;;; they are globals.
(defonce rem-a f64 7.5)
(defonce rem-na f64 -7.5)
(defonce rem-b f64 2.0)
(defonce rem-nb f64 -2.0)
(defonce rem-z f64 0.0)
(defonce rem-huge f64 1e300)
(defonce rem-a32 f32 7.5)
(defonce rem-na32 f32 -7.5)
(defonce rem-b32 f32 2.0)
(defonce rem-z32 f32 0.0)
(defn main [] i32
;; The f32 half. tan, the three inverses, the three logarithms and exp.
(show (tan-f32 0.0)) ; 0
(show (asin-f32 0.0)) ; 0
(show (acos-f32 1.0)) ; 0
(show (atan-f32 0.0)) ; 0
(show (log-f32 1.0)) ; 0
(show (log2-f32 8.0)) ; 3
(show (log10-f32 1000.0)) ; 3
(show (exp-f32 0.0)) ; 1
(println "")
(show (fmod-f32 7.0 4.0)) ; 3
;; The sign follows the dividend and not the divisor, which is the line a
;; caller reaching for a modulo gets wrong. Written down as a case.
(show (fmod-f32 -1.0 3.0)) ; -1
(show (hypot-f32 3.0 4.0)) ; 5
(show (cbrt-f32 27.0)) ; 3
;; The negative root, where (pow-f32 x 0.33333334) would be NaN: pow goes
;; through a logarithm and cbrt does not.
(show (cbrt-f32 -8.0)) ; -2
(show (abs-f32 -2.5)) ; 2.5
(println "")
;; The f64 half, at the same exact values. This block is the whole point of
;; the f64 face existing: before it, every one of these was a cast down to
;; f32 and back, and the cast down is where the precision went.
(show64 (sqrt-f64 16.0)) ; 4
(show64 (sin-f64 0.0)) ; 0
(show64 (cos-f64 0.0)) ; 1
(show64 (tan-f64 0.0)) ; 0
(show64 (asin-f64 0.0)) ; 0
(show64 (acos-f64 1.0)) ; 0
(show64 (atan-f64 0.0)) ; 0
(show64 (atan2-f64 0.0 1.0)) ; 0
(println "")
(show64 (log-f64 1.0)) ; 0
(show64 (log2-f64 1024.0)) ; 10
(show64 (log10-f64 100.0)) ; 2
(show64 (exp-f64 0.0)) ; 1
(show64 (pow-f64 2.0 10.0)) ; 1024
(show64 (fmod-f64 7.0 4.0)) ; 3
(show64 (hypot-f64 3.0 4.0)) ; 5
(show64 (cbrt-f64 8.0)) ; 2
(show64 (abs-f64 -1.5)) ; 1.5
(println "")
;; The f64 rounding family, which is libm's where the f32 one is Flan's —
;; and it agrees with the Flan one where they overlap: half away from zero,
;; so -2.5 goes to -3 and not to -2.
(show64 (floor-f64 -2.5)) ; -3
(show64 (ceil-f64 -2.5)) ; -2
(show64 (round-f64 -2.5)) ; -3
(show64 (round-f64 2.5)) ; 3
(println "")
;; Integer magnitude, one generic under integer? — the per-width pair
;; collapsed into it (FIX.org 2026-09-20). Two widths, two copies.
(print (abs -7)) (print " ") ; 7
(print (abs (i64 -7))) (print " ") ; 7
(print (abs 7)) (print " ") ; 7
;; tau is 2pi at both widths. Pinning the relation rather than the digits is
;; what catches a constant written to too few of them.
(print (= tau-f32 (* 2.0 pi-f32))) (print " ")
(print (= tau-f64 (* 2.0 pi-f64)))
(println "")
;; pi is the one value here that can be pinned without pinning a libm: it is
;; a literal the compiler rounds, so it is the same on every target.
(println (and (> pi-f64 3.14159265) (< pi-f64 3.14159266)))
;; The operator spelling of the same function. A typed float (% x y) is
;; fmod: LLVM lowers it to `frem`, which at -O0 becomes a call to fmod or
;; fmodf, and the x86 backend calls the same two symbols. Everything here
;; comes through a global rather than a literal for the reason arith.flan
;; gives — a literal pair is folded before either backend sees an operator,
;; and the folded answer would be evidence about the constant folder and
;; not about the lowering.
;;
;; Six values on the first line: the four sign combinations, where a modulo
;; written in place of a remainder disagrees — the sign follows the dividend
;; — and then the f32 pair, asking fmodf the same. The second line is the
;; two answers IEEE defines where an integer % would have died: a zero
;; divisor and a NaN dividend are both NaN, not a signal.
(show64 (% rem-a rem-b)) ; 1.5
(show64 (% rem-na rem-b)) ; -1.5
(show64 (% rem-a rem-nb)) ; 1.5
(show64 (% rem-na rem-nb)) ; -1.5
(show (% rem-a32 rem-b32)) ; 1.5
(show (% rem-na32 rem-b32)) ; -1.5
(println "")
(show64 (% rem-a rem-z)) ; nan
(show64 (% (/ rem-z rem-z) rem-b)) ; nan
(show (% rem-a32 rem-z32)) ; nan
;; A quotient past anything an integer could name, which is where a
;; remainder written as x - trunc(x/y)*y has nothing left to truncate.
(show64 (% rem-huge rem-b)) ; 0
(show64 (% rem-b rem-huge)) ; 2
(println "")
0)