aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/test/lux/math.lux
blob: 0ed9cab76289353743e121310718f50f6e1a139f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
(.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]))))
            ))))