(.module: [lux #* [control [monad (#+ Monad do)]] [data ["." bit ("#;." equivalence)] [number ["." frac ("#;." number)]]] ["&" math infix ["r" random]]] lux/test) (def: (within? margin-of-error standard value) (-> Frac Frac Frac Bit) (f/< margin-of-error (frac;abs (f/- standard value)))) (def: margin Frac +0.0000001) (def: (trigonometric-symmetry forward backward angle) (-> (-> Frac Frac) (-> Frac Frac) Frac Bit) (let [normal (|> angle forward backward)] (|> normal forward backward (within? margin normal)))) (context: "Trigonometry" (<| (times 100) (do @ [angle (|> r.frac (:: @ map (f/* &.tau)))] ($_ seq (test "Sine and arc-sine are inverse functions." (trigonometric-symmetry &.sin &.asin angle)) (test "Cosine and arc-cosine are inverse functions." (trigonometric-symmetry &.cos &.acos angle)) (test "Tangent and arc-tangent are inverse functions." (trigonometric-symmetry &.tan &.atan angle)) )))) (context: "Rounding" (<| (times 100) (do @ [sample (|> r.frac (:: @ map (f/* +1000.0)))] ($_ seq (test "The ceiling will be an integer value, and will be >= the original." (let [ceil'd (&.ceil sample)] (and (|> ceil'd frac-to-int int-to-frac (f/= ceil'd)) (f/>= sample ceil'd) (f/<= +1.0 (f/- sample ceil'd))))) (test "The floor will be an integer value, and will be <= the original." (let [floor'd (&.floor sample)] (and (|> floor'd frac-to-int int-to-frac (f/= floor'd)) (f/<= sample floor'd) (f/<= +1.0 (f/- floor'd sample))))) (test "The round will be an integer value, and will be < or > or = the original." (let [round'd (&.round sample)] (and (|> round'd frac-to-int int-to-frac (f/= round'd)) (f/<= +1.0 (frac;abs (f/- sample round'd)))))) )))) (context: "Exponentials and logarithms" (<| (times 100) (do @ [sample (|> r.frac (:: @ map (f/* +10.0)))] (test "Logarithm is the inverse of exponential." (|> sample &.exp &.log (within? +1.0e-15 sample)))))) (context: "Greatest-Common-Divisor and Least-Common-Multiple" (<| (times 100) (do @ [#let [gen-nat (|> r.nat (:: @ map (|>> (n/% 1000) (n/max 1))))] x gen-nat y gen-nat] ($_ seq (test "GCD" (let [gcd (&.n/gcd x y)] (and (n/= 0 (n/% gcd x)) (n/= 0 (n/% gcd y)) (n/>= 1 gcd)))) (test "LCM" (let [lcm (&.n/lcm x y)] (and (n/= 0 (n/% x lcm)) (n/= 0 (n/% y lcm)) (n/<= (n/* x y) lcm)))) )))) (context: "Infix syntax" (<| (times 100) (do @ [x r.nat y r.nat z r.nat theta r.frac #let [top (|> x (n/max y) (n/max z)) bottom (|> x (n/min y) (n/min z))]] ($_ seq (test "Constant values don't change." (n/= x (infix x))) (test "Can call binary functions." (n/= (&.n/gcd y x) (infix [x &.n/gcd y]))) (test "Can call unary functions." (f/= (&.sin theta) (infix [&.sin theta]))) (test "Can use regular syntax in the middle of infix code." (n/= (&.n/gcd 450 (n/* 3 9)) (infix [(n/* 3 9) &.n/gcd 450]))) (test "Can use non-numerical functions/macros as operators." (bit;= (and (n/< y x) (n/< z y)) (infix [[x n/< y] and [y n/< z]]))) (test "Can combine bit operations in special ways via special keywords." (and (bit;= (and (n/< y x) (n/< z y)) (infix [#and x n/< y n/< z])) (bit;= (and (n/< y x) (n/> z y)) (infix [#and x n/< y n/> z])))) ))))