;; ========================================================================== ;; 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 ;; -------------------------------------------------------------------------- (defsuite "numeric-tower:division" (deftest "exact division value" (assert= (/ 6 2) 3)) (deftest "inexact division value" (assert= (/ 1 4) 0.25)) (deftest "float / float = float" (assert (float? (/ 3.5 2.5)))) (deftest "rational / int = rational" (assert (rational? (/ 1/2 2)))) (deftest "rational division value" (assert= (/ 1/2 2) 1/4))) ;; -------------------------------------------------------------------------- ;; 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 rational" (assert (number? 1/3))) (deftest "number? on string" (assert (not (number? "42")))) (deftest "exact? on int" (assert (exact? 1))) (deftest "exact? on rational" (assert (exact? 1/3))) (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 "exact->inexact rational" (assert= (exact->inexact 1/4) 0.25)) (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")))