;; ========================================================================== ;; test-rationals.sx — Rational number type: literals, arithmetic, tower ;; ;; Note: in the JS host, (/ int int) returns float (backward-compatible). ;; Use rational literals (1/3, 3/4) or make-rational for exact rationals. ;; ========================================================================== ;; -------------------------------------------------------------------------- ;; Literals and type ;; -------------------------------------------------------------------------- (defsuite "rationals:literals" (deftest "1/3 is rational" (assert (rational? 1/3))) (deftest "1/2 is rational" (assert (rational? 1/2))) (deftest "2/3 is rational" (assert (rational? 2/3))) (deftest "literal numerator 1/3" (assert= (numerator 1/3) 1)) (deftest "literal denominator 1/3" (assert= (denominator 1/3) 3)) (deftest "literal numerator 2/3" (assert= (numerator 2/3) 2)) (deftest "auto-reduce 2/4 = 1/2" (assert= 2/4 1/2)) (deftest "auto-reduce 6/9 = 2/3" (assert= 6/9 2/3)) (deftest "negative literal" (assert= (numerator -1/3) -1))) ;; -------------------------------------------------------------------------- ;; Constructor and predicates ;; -------------------------------------------------------------------------- (defsuite "rationals:constructor" (deftest "make-rational basic" (assert (rational? (make-rational 1 3)))) (deftest "make-rational reduces" (assert= (make-rational 2 4) 1/2)) (deftest "make-rational exact int" (assert (integer? (make-rational 6 3)))) (deftest "make-rational 6/3 = 2" (assert= (make-rational 6 3) 2)) (deftest "make-rational negative" (assert= (numerator (make-rational -1 3)) -1)) (deftest "make-rational neg denom" (assert= (numerator (make-rational 1 -3)) -1)) (deftest "rational? on int" (assert (not (rational? 5)))) (deftest "rational? on float" (assert (not (rational? 1.5)))) (deftest "rational? on string" (assert (not (rational? "1/2")))) (deftest "number? on rational" (assert (number? 1/3))) (deftest "exact? on rational" (assert (exact? 1/3))) (deftest "inexact? on rational" (assert (not (inexact? 1/3)))) (deftest "integer? on rational" (assert (not (integer? 1/3)))) (deftest "dict? on rational" (assert (not (dict? 1/3))))) ;; -------------------------------------------------------------------------- ;; Accessors ;; -------------------------------------------------------------------------- (defsuite "rationals:accessors" (deftest "numerator 1/3" (assert= (numerator 1/3) 1)) (deftest "denominator 1/3" (assert= (denominator 1/3) 3)) (deftest "numerator 3/4" (assert= (numerator 3/4) 3)) (deftest "denominator 3/4" (assert= (denominator 3/4) 4)) (deftest "numerator of int" (assert= (numerator 5) 5)) (deftest "denominator of int" (assert= (denominator 5) 1))) ;; -------------------------------------------------------------------------- ;; Arithmetic ;; -------------------------------------------------------------------------- (defsuite "rationals:arithmetic" (deftest "add two rationals" (assert= (+ 1/3 1/3) 2/3)) (deftest "add to integer" (assert= (+ 1 1/2) 3/2)) (deftest "add integer to rational" (assert= (+ 1/2 1) 3/2)) (deftest "add reduces" (assert= (+ 1/6 1/6) 1/3)) (deftest "add to whole number" (assert (integer? (+ 1/2 1/2)))) (deftest "add whole = 1" (assert= (+ 1/2 1/2) 1)) (deftest "subtract rationals" (assert= (- 3/4 1/4) 1/2)) (deftest "subtract int from rational" (assert= (- 3/2 1) 1/2)) (deftest "negate rational" (assert= (- 1/3) -1/3)) (deftest "multiply rationals" (assert= (* 2/3 3/4) 1/2)) (deftest "multiply int and rational" (assert= (* 2 1/3) 2/3)) (deftest "multiply reduces to int" (assert (integer? (* 3 1/3)))) (deftest "divide rational by int" (assert= (/ 2/3 2) 1/3)) (deftest "divide rational by rational" (assert= (/ 1/2 1/4) 2)) (deftest "divide rational gives int when exact" (assert (integer? (/ 1/2 1/2))))) ;; -------------------------------------------------------------------------- ;; Float contagion ;; -------------------------------------------------------------------------- (defsuite "rationals:float-contagion" (deftest "rational + float = float" (assert (float? (+ 1/3 0.5)))) (deftest "float + rational = float" (assert (float? (+ 0.5 1/3)))) (deftest "rational * float = float" (assert (float? (* 1/2 2)))) (deftest "rational - float = float" (assert (float? (- 1/2 0.1))))) ;; -------------------------------------------------------------------------- ;; Comparison ;; -------------------------------------------------------------------------- (defsuite "rationals:comparison" (deftest "equal rationals" (assert (= 1/2 1/2))) (deftest "equal reduced" (assert (= 2/4 1/2))) (deftest "not equal" (assert (not (= 1/3 1/2)))) (deftest "less than" (assert (< 1/3 1/2))) (deftest "less than int" (assert (< 1/3 1))) (deftest "greater than" (assert (> 2/3 1/2))) (deftest "less equal" (assert (<= 1/3 1/3))) (deftest "greater equal" (assert (>= 2/3 2/3))) (deftest "rational less than float" (assert (< 1/3 0.5)))) ;; -------------------------------------------------------------------------- ;; Coercion ;; -------------------------------------------------------------------------- (defsuite "rationals:coercion" (deftest "exact->inexact 1/2" (assert= (exact->inexact 1/2) 0.5)) (deftest "exact->inexact 1/4" (assert= (exact->inexact 1/4) 0.25)) (deftest "exact->inexact 1/3 is float" (assert (float? (exact->inexact 1/3)))) (deftest "number->string 1/2" (assert= (number->string 1/2) "1/2")) (deftest "number->string 3/4" (assert= (number->string 3/4) "3/4")))