print-str, print-i64, print-f64, print-bytes, print-line and newline leave the prelude. print and println are the whole printing surface now, and print is the better call at every one of the sites that used them: it is the same structural walk without the newline, so the no-newline case the family was kept for is covered, and it takes the value as it is. The old print-i64 forced an explicit (i64 x) at every call site, because this language widens nothing implicitly; that cast is gone from 127 places. Dropping it moves one answer. hash-grid returns u64, and the cast through the signed printer showed sand-headless's hash as -2851001042534928384. print routes a u64 through flan_u64_to_bytes, so it now prints 15595743031174623232 — the same 64 bits, read as the unsigned number they are. The pinned expectation follows the correction. test-flan-dev.el and test_session.ml both reached for print-line as "a name the prelude has"; they reach for rand-seed instead.
61 lines
2.7 KiB
Plaintext
61 lines
2.7 KiB
Plaintext
;;;; The prelude's rounding, and sqrt.
|
|
;;;;
|
|
;;;; Every input is one a plausible wrong implementation gets wrong. The
|
|
;;;; negatives are the whole point: a floor written as a bare cast truncates
|
|
;;;; toward zero and answers -2 for -2.5, and a round written as
|
|
;;;; (floor-f32 (+ x 0.5)) answers -2 for -2.5 as well, where C's round says
|
|
;;;; -3. The exact halves appear on both signs for that reason. The values
|
|
;;;; that are already integers check that the correction does *not* fire —
|
|
;;;; a floor that always subtracts one turns 3.0 into 2.0 — and 16777216.0 is
|
|
;;;; past 2^24, where an f32 has no fractional bits and the guard, not the
|
|
;;;; cast, has to produce the answer.
|
|
|
|
(defn show [x f32]
|
|
(print x)
|
|
(print " "))
|
|
|
|
(defn main [] i32
|
|
;; floor: down on both signs, and unmoved on the integers.
|
|
(show (floor-f32 2.7)) (show (floor-f32 2.0)) (show (floor-f32 2.3))
|
|
(show (floor-f32 -2.7)) (show (floor-f32 -2.0)) (show (floor-f32 -2.3))
|
|
(show (floor-f32 0.5)) (show (floor-f32 -0.5))
|
|
(println "")
|
|
|
|
;; ceil: up on both signs. -2.7 must give -2, which is where a ceil written
|
|
;; as "floor plus one" goes wrong.
|
|
(show (ceil-f32 2.7)) (show (ceil-f32 2.0)) (show (ceil-f32 2.3))
|
|
(show (ceil-f32 -2.7)) (show (ceil-f32 -2.0)) (show (ceil-f32 -2.3))
|
|
(show (ceil-f32 0.5)) (show (ceil-f32 -0.5))
|
|
(println "")
|
|
|
|
;; Zero keeps its sign through floor, which is what the (= x 0.0) guard in
|
|
;; it is for and the only place that guard is observable: the cast it skips
|
|
;; would turn -0.0 into +0.0, and %g prints the difference. Drop the guard
|
|
;; and the third column here reads 0 instead of -0.
|
|
(show (floor-f32 0.0)) (show (ceil-f32 0.0)) (show (floor-f32 -0.0))
|
|
(println "")
|
|
|
|
;; round: half away from zero on both signs, so -2.5 is -3 and not -2.
|
|
(show (round-f32 2.4)) (show (round-f32 2.5)) (show (round-f32 2.6))
|
|
(show (round-f32 -2.4)) (show (round-f32 -2.5)) (show (round-f32 -2.6))
|
|
(show (round-f32 0.5)) (show (round-f32 -0.5))
|
|
(println "")
|
|
|
|
;; Past 2^24 there is no fraction left; the answer is the input, and the
|
|
;; cast that would produce it is out of i32's range on the way there.
|
|
(show (floor-f32 16777216.0)) (show (ceil-f32 16777216.0))
|
|
(show (round-f32 16777216.0)) (show (floor-f32 -16777216.0))
|
|
(println "")
|
|
|
|
;; sqrt, including the two values a wrong-sense iteration still passes
|
|
;; (0 and 1) and one that is not a perfect square.
|
|
(show (sqrt-f32 0.0)) (show (sqrt-f32 1.0)) (show (sqrt-f32 4.0))
|
|
(show (sqrt-f32 2.0)) (show (sqrt-f32 0.25)) (show (sqrt-f32 1e6))
|
|
(println "")
|
|
|
|
;; A squared distance through sqrt, which is what a game actually calls it
|
|
;; for: 3-4-5 exactly, so a last-bit error would show.
|
|
(show (sqrt-f32 (+ (* 3.0 3.0) (* 4.0 4.0))))
|
|
(println "")
|
|
0)
|