;; numerics.sx — Phase 10 numeric tower verification.
;;
;; Practical integer-precision limit in Haskell-on-SX:
;;   • Raw SX `(* a b)` stays exact up to ±2^62 (≈ 4.6e18, OCaml int63).
;;   • BUT the Haskell tokenizer/parser parses an integer literal as a float
;;     once it exceeds 2^53 (≈ 9.007e15). Once any operand is a float, the
;;     binop result is a float (and decimal-precision is lost past 2^53).
;;   • Therefore: programs that stay below ~9e15 are exact; larger literals
;;     or accumulated products silently become floats. `factorial 18` is the
;;     last factorial that stays exact (6.4e15); `factorial 19` already floats.
;;
;; In Haskell terms, `Int` and `Integer` both currently map to SX number, so
;; we don't yet support arbitrary-precision Integer. Documented; unbounded
;; Integer is out of scope for Phase 10 — see Phase 11+ if it becomes needed.

(define
  hk-as-list
  (fn
    (xs)
    (cond
      ((and (list? xs) (= (first xs) "[]")) (list))
      ((and (list? xs) (= (first xs) ":"))
        (cons (nth xs 1) (hk-as-list (nth xs 2))))
      (:else xs))))

(hk-test
  "factorial 10 = 3628800 (small, exact)"
  (hk-deep-force
    (hk-run "fact 0 = 1\nfact n = n * fact (n - 1)\nmain = fact 10"))
  3628800)

(hk-test
  "factorial 15 = 1307674368000 (mid-range, exact)"
  (hk-deep-force
    (hk-run "fact 0 = 1\nfact n = n * fact (n - 1)\nmain = fact 15"))
  1307674368000)

(hk-test
  "factorial 18 = 6402373705728000 (last exact factorial)"
  (hk-deep-force
    (hk-run "fact 0 = 1\nfact n = n * fact (n - 1)\nmain = fact 18"))
  6402373705728000)

(hk-test
  "1000000 * 1000000 = 10^12 (exact)"
  (hk-deep-force (hk-run "main = 1000000 * 1000000"))
  1000000000000)

(hk-test
  "1000000000 * 1000000000 = 10^18 (exact, at boundary)"
  (hk-deep-force (hk-run "main = 1000000000 * 1000000000"))
  1e+18)

(hk-test
  "2^62 boundary: pow accumulates exactly"
  (hk-deep-force
    (hk-run "pow b 0 = 1\npow b n = b * pow b (n - 1)\nmain = pow 2 62"))
  4.6116860184273879e+18)

(hk-test
  "show factorial 12 = 479001600 (whole, fits in 32-bit)"
  (hk-deep-force
    (hk-run "fact 0 = 1\nfact n = n * fact (n - 1)\nmain = show (fact 12)"))
  "479001600")

(hk-test
  "negate large positive — preserves magnitude"
  (hk-deep-force (hk-run "main = negate 1000000000000000000"))
  -1e+18)

(hk-test
  "abs negative large — preserves magnitude"
  (hk-deep-force (hk-run "main = abs (negate 1000000000000000000)"))
  1e+18)

(hk-test
  "div on large ints"
  (hk-deep-force (hk-run "main = div 1000000000000000000 1000000000"))
  1000000000)

(hk-test
  "fromIntegral 42 = 42 (identity in our runtime)"
  (hk-deep-force (hk-run "main = fromIntegral 42"))
  42)

(hk-test
  "fromIntegral preserves negative"
  (hk-deep-force (hk-run "main = fromIntegral (negate 7)"))
  -7)

(hk-test
  "fromIntegral round-trips through arithmetic"
  (hk-deep-force (hk-run "main = fromIntegral 5 + fromIntegral 3"))
  8)

(hk-test
  "fromIntegral in a program (mixing with map)"
  (hk-as-list (hk-deep-force (hk-run "main = map fromIntegral [1,2,3]")))
  (list 1 2 3))

(hk-test
  "toInteger 100 = 100 (identity)"
  (hk-deep-force (hk-run "main = toInteger 100"))
  100)

(hk-test
  "fromInteger 7 = 7 (identity)"
  (hk-deep-force (hk-run "main = fromInteger 7"))
  7)

(hk-test
  "toInteger / fromInteger round-trip"
  (hk-deep-force (hk-run "main = fromInteger (toInteger 42)"))
  42)

(hk-test
  "toInteger preserves negative"
  (hk-deep-force (hk-run "main = toInteger (negate 13)"))
  -13)

(hk-test
  "show 3.14 = 3.14"
  (hk-deep-force (hk-run "main = show 3.14"))
  "3.14")

(hk-test
  "show 1.0e10 — whole-valued float renders as decimal (int/float ambiguity)"
  (hk-deep-force (hk-run "main = show 1.0e10"))
  "10000000000")

(hk-test
  "show 0.001 uses scientific form (sub-0.1)"
  (hk-deep-force (hk-run "main = show 0.001"))
  "1.0e-3")

(hk-test
  "show negative float"
  (hk-deep-force (hk-run "main = show (negate 3.14)"))
  "-3.14")

(hk-test "sqrt 16 = 4" (hk-deep-force (hk-run "main = sqrt 16")) 4)

(hk-test "floor 3.7 = 3" (hk-deep-force (hk-run "main = floor 3.7")) 3)

(hk-test "ceiling 3.2 = 4" (hk-deep-force (hk-run "main = ceiling 3.2")) 4)

(hk-test
  "ceiling on whole = self"
  (hk-deep-force (hk-run "main = ceiling 4"))
  4)

(hk-test "round 2.6 = 3" (hk-deep-force (hk-run "main = round 2.6")) 3)

(hk-test
  "truncate -3.7 = -3"
  (hk-deep-force (hk-run "main = truncate (negate 3.7)"))
  -3)

(hk-test "recip 4.0 = 0.25" (hk-deep-force (hk-run "main = recip 4.0")) 0.25)

(hk-test "1.0 / 4.0 = 0.25" (hk-deep-force (hk-run "main = 1.0 / 4.0")) 0.25)

(hk-test
  "fromRational 0.5 = 0.5 (identity)"
  (hk-deep-force (hk-run "main = fromRational 0.5"))
  0.5)

(hk-test "pi ≈ 3.14159" (hk-deep-force (hk-run "main = pi")) 3.14159)

(hk-test "exp 0 = 1" (hk-deep-force (hk-run "main = exp 0")) 1)

(hk-test "sin 0 = 0" (hk-deep-force (hk-run "main = sin 0")) 0)

(hk-test "cos 0 = 1" (hk-deep-force (hk-run "main = cos 0")) 1)

(hk-test "2 ** 10 = 1024" (hk-deep-force (hk-run "main = 2 ** 10")) 1024)

(hk-test "log (exp 5) ≈ 5" (hk-deep-force (hk-run "main = log (exp 5)")) 5)

{:fails hk-test-fails :pass hk-test-pass :fail hk-test-fail}
