;; ========================================================================== ;; test-numeric-tower.sx — Numeric tower: Integer vs Float distinction ;; ;; Tests for float contagion, integer arithmetic, predicates, ;; coercions, parsing, and rendering. ;; ;; Note: Use fractional floats (1.5, 3.14) or exact->inexact for round floats, ;; since the SX serializer renders Number 1.0 as "1" (int form). ;; ========================================================================== ;; -------------------------------------------------------------------------- ;; Integer arithmetic — result stays Integer when all args are Integer ;; -------------------------------------------------------------------------- (defsuite "numeric-tower:int-arithmetic" (deftest "int + int = int" (assert (integer? (+ 1 2)))) (deftest "int + int value" (assert= (+ 1 2) 3)) (deftest "int - int = int" (assert (integer? (- 10 3)))) (deftest "int - int value" (assert= (- 10 3) 7)) (deftest "int * int = int" (assert (integer? (* 4 5)))) (deftest "int * int value" (assert= (* 4 5) 20)) (deftest "zero identity" (assert= (+ 0 0) 0)) (deftest "negative int" (assert= (- 0 5) -5)) (deftest "int negation is int" (assert (integer? (- 0 7)))) (deftest "large int product" (assert= (* 100 100) 10000))) ;; -------------------------------------------------------------------------- ;; Float contagion — any float arg promotes result to float ;; -------------------------------------------------------------------------- (defsuite "numeric-tower:float-contagion" (deftest "int + float = float" (assert (float? (+ 1 1.5)))) (deftest "int + float value" (assert= (+ 1 1.5) 2.5)) (deftest "float + int = float" (assert (float? (+ 1.5 2)))) (deftest "float + float = float" (assert (float? (+ 1.5 2.5)))) (deftest "int * float = float" (assert (float? (* 2 1.5)))) (deftest "int * float value" (assert= (* 2 1.5) 3)) (deftest "int - float = float" (assert (float? (- 5 2.5)))) (deftest "float - int = float" (assert (float? (- 5.5 2)))) (deftest "three args with float" (assert (float? (+ 1 2 3.5)))) (deftest "exact->inexact promotes to float" (assert (float? (exact->inexact 5))))) ;; -------------------------------------------------------------------------- ;; Division always returns float ;; -------------------------------------------------------------------------- (defsuite "numeric-tower:division" (deftest "int / int = float" (assert (float? (/ 6 2)))) (deftest "exact division value" (assert= (/ 6 2) 3)) (deftest "inexact division" (assert= (/ 1 4) 0.25)) (deftest "float / float = float" (assert (float? (/ 3.5 2.5))))) ;; -------------------------------------------------------------------------- ;; Type predicates ;; -------------------------------------------------------------------------- (defsuite "numeric-tower:predicates" (deftest "integer? on int" (assert (integer? 42))) (deftest "integer? on negative" (assert (integer? -7))) (deftest "integer? on zero" (assert (integer? 0))) (deftest "integer? on float-int" (assert (integer? (exact->inexact 2)))) (deftest "integer? on fractional float" (assert (not (integer? 1.5)))) (deftest "float? on 1.5" (assert (float? 1.5))) (deftest "float? on exact->inexact" (assert (float? (exact->inexact 2)))) (deftest "float? on int" (assert (not (float? 42)))) (deftest "number? on int" (assert (number? 42))) (deftest "number? on float" (assert (number? 3.14))) (deftest "number? on string" (assert (not (number? "42")))) (deftest "exact? on int" (assert (exact? 1))) (deftest "exact? on exact->inexact" (assert (not (exact? (exact->inexact 1))))) (deftest "inexact? on 1.5" (assert (inexact? 1.5))) (deftest "inexact? on int" (assert (not (inexact? 3))))) ;; -------------------------------------------------------------------------- ;; Coercions ;; -------------------------------------------------------------------------- (defsuite "numeric-tower:coercions" (deftest "exact->inexact int" (assert= (exact->inexact 3) 3)) (deftest "exact->inexact produces float" (assert (float? (exact->inexact 5)))) (deftest "exact->inexact float passthrough" (assert= (exact->inexact 1.5) 1.5)) (deftest "inexact->exact 1.5" (assert= (inexact->exact 1.5) 2)) (deftest "inexact->exact produces int" (assert (integer? (inexact->exact (exact->inexact 4))))) (deftest "inexact->exact 2.7" (assert= (inexact->exact 2.7) 3)) (deftest "inexact->exact int passthrough" (assert= (inexact->exact 5) 5))) ;; -------------------------------------------------------------------------- ;; floor / ceiling / truncate / round — return Integer for floats ;; -------------------------------------------------------------------------- (defsuite "numeric-tower:rounding" (deftest "floor 3.7" (assert= (floor 3.7) 3)) (deftest "floor produces int" (assert (integer? (floor 3.7)))) (deftest "floor negative" (assert= (floor -2.3) -3)) (deftest "truncate 3.9" (assert= (truncate 3.9) 3)) (deftest "truncate negative" (assert= (truncate -3.9) -3)) (deftest "truncate produces int" (assert (integer? (truncate 3.9)))) (deftest "round 2.3 down" (assert= (round 2.3) 2)) (deftest "round produces int" (assert (integer? (round 2.3)))) (deftest "floor of int passthrough" (assert= (floor 5) 5)) (deftest "floor of int stays int" (assert (integer? (floor 5))))) ;; -------------------------------------------------------------------------- ;; parse-number distinguishes int vs float strings ;; -------------------------------------------------------------------------- (defsuite "numeric-tower:parse-number" (deftest "parse-number int string" (assert= (parse-number "42") 42)) (deftest "parse-number int is integer?" (assert (integer? (parse-number "42")))) (deftest "parse-number 3.14" (assert= (parse-number "3.14") 3.14)) (deftest "parse-number float is float?" (assert (float? (parse-number "3.14")))) (deftest "parse-number 1.5 is float?" (assert (float? (parse-number "1.5")))) (deftest "parse-number negative int" (assert= (parse-number "-5") -5)) (deftest "parse-number negative int is integer?" (assert (integer? (parse-number "-5")))) (deftest "parse-int returns integer" (assert (integer? (parse-int "7")))) (deftest "parse-int value" (assert= (parse-int "7") 7))) ;; -------------------------------------------------------------------------- ;; Equality across numeric types ;; -------------------------------------------------------------------------- (defsuite "numeric-tower:equality" (deftest "int = same int" (assert= 5 5)) (deftest "int = float eq" (assert (= 1 (exact->inexact 1)))) (deftest "float = int eq" (assert (= (exact->inexact 1) 1))) (deftest "int != different int" (assert (!= 1 2))) (deftest "int < float" (assert (< 1 1.5))) (deftest "float > int" (assert (> 2.5 2))) (deftest "int <= float" (assert (<= 2 2.5))) (deftest "int >= int" (assert (>= 3 3)))) ;; -------------------------------------------------------------------------- ;; mod / remainder / modulo with integers ;; -------------------------------------------------------------------------- (defsuite "numeric-tower:modulo" (deftest "mod int int = int" (assert (integer? (mod 10 3)))) (deftest "mod value" (assert= (mod 10 3) 1)) (deftest "remainder int int = int" (assert (integer? (remainder 10 3)))) (deftest "remainder value" (assert= (remainder 10 3) 1))) ;; -------------------------------------------------------------------------- ;; min / max with mixed types ;; -------------------------------------------------------------------------- (defsuite "numeric-tower:min-max" (deftest "min two ints" (assert= (min 3 7) 3)) (deftest "min int result type" (assert (integer? (min 3 7)))) (deftest "max two ints" (assert= (max 3 7) 7)) (deftest "min with float" (assert= (min 3 2.5) 2.5)) (deftest "max with float" (assert= (max 3 3.5) 3.5))) ;; -------------------------------------------------------------------------- ;; str rendering of int vs float ;; -------------------------------------------------------------------------- (defsuite "numeric-tower:stringify" (deftest "str of int" (assert= (str 42) "42")) (deftest "str of negative int" (assert= (str -5) "-5")) (deftest "str of 3.14" (assert= (str 3.14) "3.14")) (deftest "str of 1.5" (assert= (str 1.5) "1.5")))