changed README.md
 
@@ -45,6 +45,7 @@ The Math module adds many useful functions that extend Elixir's standard library
45
45
- `Math.Enum.product(collection)` The result of multiplying all elements in the passed collection.
46
46
- `Math.Enum.mean(collection)` the mean of the numbers in the collection.
47
47
- `Math.Enum.median(collection)` the median of the numbers in the collection.
48
+ - `Math.Enum.mode(collection)` the mode of the numbers in the collection.
48
49
49
50
## Installation
50
51
 
@@ -54,7 +55,7 @@ Math is [available in Hex](https://hex.pm/packages/math). The package can be ins
54
55
55
56
def deps do
56
57
[
57
- {:math, "~> 0.3.0"}
58
+ {:math, "~> 0.3.1"}
58
59
]
59
60
end
60
61
 
@@ -69,6 +70,8 @@ Math is [available in Hex](https://hex.pm/packages/math). The package can be ins
69
70
(Importing allows usage of the `<~>` operator)
70
71
71
72
## Changelog
73
+ - 0.4.0 Adds `Math.Enum.mode/1`.
74
+ - 0.3.1 Updates formatting to hide warnings in newer versions of Elixir.
72
75
- 0.3.0 Fixed incorrect median for lists with even number of items. Updated tests.
73
76
- 0.2.0 Added `factorial/1`, `nth_sqrt/2`, `k_permutations/2`, `k_combinations/2`, `gcd/2`, `lcm/2` and `Math.Enum` functions. Improved documentation.
74
77
- 0.1.0 Added integer variant of `pow/1`, `isqrt/2`, `deg2rad/1`, `rad2deg/1`. Improved documentation.
changed hex_metadata.config
 
@@ -10,4 +10,4 @@
10
10
{<<"links">>,[{<<"GitHub">>,<<"https://github.com/folz/math">>}]}.
11
11
{<<"name">>,<<"math">>}.
12
12
{<<"requirements">>,[]}.
13
- {<<"version">>,<<"0.3.1">>}.
13
+ {<<"version">>,<<"0.4.0">>}.
changed lib/math.ex
 
@@ -14,7 +14,6 @@ defmodule Math do
14
14
@type x :: number
15
15
@type y :: number
16
16
17
-
18
17
@doc """
19
18
The mathematical constant *π* (pi).
20
19
 
@@ -24,8 +23,7 @@ defmodule Math do
24
23
@spec pi :: float
25
24
defdelegate pi, to: :math
26
25
27
- @rad_in_deg (180/:math.pi)
28
-
26
+ @rad_in_deg 180 / :math.pi()
29
27
30
28
@doc """
31
29
The mathematical constant *τ* (tau).
 
@@ -59,18 +57,20 @@ defmodule Math do
59
57
"""
60
58
@spec number <~> number :: boolean
61
59
def x <~> y do
62
- absX = abs(x)
63
- absY = abs(y)
60
+ abs_x = abs(x)
61
+ abs_y = abs(y)
64
62
diff = abs(x - y)
65
63
66
64
# Hacky comparison for floats that are nearly equal.
67
65
cond do
68
66
x == y ->
69
67
true
68
+
70
69
x == 0 or y == 0 ->
71
70
diff < @epsilon
71
+
72
72
true ->
73
- diff / min((absX + absY), @max_value) < @epsilon
73
+ diff / min(abs_x + abs_y, @max_value) < @epsilon
74
74
end
75
75
end
76
76
 
@@ -116,9 +116,9 @@ defmodule Math do
116
116
defp _pow(x, n, y \\ 1)
117
117
defp _pow(_x, 0, y), do: y
118
118
defp _pow(x, 1, y), do: x * y
119
- defp _pow(x, n, y) when (n < 0), do: _pow(1 / x, -n, y)
119
+ defp _pow(x, n, y) when n < 0, do: _pow(1 / x, -n, y)
120
120
defp _pow(x, n, y) when rem(n, 2) == 0, do: _pow(x * x, div(n, 2), y)
121
- defp _pow(x, n, y), do: _pow(x * x, div((n - 1), 2), x * y)
121
+ defp _pow(x, n, y), do: _pow(x * x, div(n - 1, 2), x * y)
122
122
123
123
@doc """
124
124
Calculates the non-negative square root of *x*.
 
@@ -159,9 +159,9 @@ defmodule Math do
159
159
@spec isqrt(integer) :: integer
160
160
def isqrt(x)
161
161
162
- def isqrt(x) when x < 0, do: raise ArithmeticError
162
+ def isqrt(x) when x < 0, do: raise(ArithmeticError)
163
163
164
- def isqrt(x), do: _isqrt(x, 1, div((1 + x), 2))
164
+ def isqrt(x), do: _isqrt(x, 1, div(1 + x, 2))
165
165
166
166
defp _isqrt(x, m, n) when abs(m - n) <= 1 and n * n <= x, do: n
167
167
defp _isqrt(_x, m, n) when abs(m - n) <= 1, do: n - 1
 
@@ -170,7 +170,6 @@ defmodule Math do
170
170
_isqrt(x, n, div(n + div(x, n), 2))
171
171
end
172
172
173
-
174
173
#
175
174
@doc """
176
175
Calculates the Greatest Common divisor of two numbers.
 
@@ -197,7 +196,7 @@ defmodule Math do
197
196
198
197
def gcd(0, b), do: abs(b)
199
198
def gcd(a, b) when a < 0 or b < 0, do: gcd(abs(a), abs(b))
200
- def gcd(a, b), do: gcd(b, rem(a,b))
199
+ def gcd(a, b), do: gcd(b, rem(a, b))
201
200
202
201
@doc """
203
202
Calculates the Least Common Multiple of two numbers.
 
@@ -219,11 +218,11 @@ defmodule Math do
219
218
def lcm(a, b)
220
219
221
220
def lcm(0, 0), do: 0
221
+
222
222
def lcm(a, b) do
223
223
abs(Kernel.div(a * b, gcd(a, b)))
224
224
end
225
225
226
-
227
226
@precompute_factorials_up_to 1000
228
227
@doc """
229
228
Calculates the factorial of *n*: 1 * 2 * 3 * ... * *n*
 
@@ -244,12 +243,14 @@ defmodule Math do
244
243
245
244
def factorial(0), do: 1
246
245
247
- for {n, fact} <- (1..@precompute_factorials_up_to |> Enum.scan( {0, 1}, fn n, {_prev_n, prev_fact} -> {n, n * prev_fact} end)) do
246
+ for {n, fact} <-
247
+ 1..@precompute_factorials_up_to
248
+ |> Enum.scan({0, 1}, fn n, {_prev_n, prev_fact} -> {n, n * prev_fact} end) do
248
249
def factorial(unquote(n)), do: unquote(fact)
249
250
end
250
251
251
252
def factorial(n) when n >= 0 do
252
- n * factorial(n-1)
253
+ n * factorial(n - 1)
253
254
end
254
255
255
256
@doc """
 
@@ -278,7 +279,6 @@ defmodule Math do
278
279
div(factorial(n), factorial(n - k))
279
280
end
280
281
281
-
282
282
@doc """
283
283
Calculates the k-combinations of *n*.
284
284
 
@@ -299,7 +299,6 @@ defmodule Math do
299
299
div(factorial(n), factorial(k) * factorial(n - k))
300
300
end
301
301
302
-
303
302
# Logarithms and exponentiation
304
303
305
304
@doc """
 
@@ -338,6 +337,7 @@ defmodule Math do
338
337
"""
339
338
@spec log(x, number) :: float
340
339
def log(x, x), do: 1.0
340
+
341
341
def log(x, b) do
342
342
:math.log(x) / :math.log(b)
343
343
end
 
@@ -472,5 +472,4 @@ defmodule Math do
472
472
"""
473
473
@spec atanh(x) :: float
474
474
defdelegate atanh(x), to: :math
475
-
476
475
end
changed lib/math/enum.ex
 
@@ -3,6 +3,7 @@ defmodule Math.Enum do
3
3
Math.Enum defines Math-functions that work on any collection extending the Enumerable protocol.
4
4
This means Maps, Lists, Sets, etc., and any custom collection types as well.
5
5
"""
6
+ require Integer
6
7
7
8
@doc """
8
9
Calculates the product, obtained by multiplying all elements in *collection* with eachother.
 
@@ -20,7 +21,7 @@ defmodule Math.Enum do
20
21
21
22
# General implementation for any enumerable.
22
23
def product(collection) do
23
- Enum.reduce(collection, &(&1 * &2))
24
+ Enum.reduce(collection, &*/2)
24
25
end
25
26
26
27
@doc """
 
@@ -42,11 +43,12 @@ defmodule Math.Enum do
42
43
iex> Math.Enum.mean []
43
44
nil
44
45
"""
45
- @spec mean(Enum.t) :: number
46
+ @spec mean(Enum.t()) :: number
46
47
def mean(collection)
47
48
48
49
def mean(collection) do
49
50
count = Enum.count(collection)
51
+
50
52
case count do
51
53
0 -> nil
52
54
_ -> Enum.sum(collection) / count
 
@@ -76,23 +78,53 @@ defmodule Math.Enum do
76
78
iex> Math.Enum.median []
77
79
nil
78
80
"""
79
- @spec median(Enum.t) :: number | nil
81
+ @spec median(Enum.t()) :: number | nil
80
82
def median(collection)
81
83
82
84
def median(collection) do
83
85
count = Enum.count(collection)
86
+ mid_point = div(count, 2)
87
+
84
88
cond do
85
- count == 0 -> nil
86
- rem(count, 2) == 1 -> # Middle element exists
87
- Enum.sort(collection) |> Enum.at(div(count, 2))
89
+ count == 0 ->
90
+ nil
91
+
92
+ # Middle element exists
93
+ Integer.is_odd(count) ->
94
+ collection
95
+ |> Enum.sort()
96
+ |> Enum.fetch!(mid_point)
97
+
88
98
true ->
89
- # Take two middle-most elements.
90
- sorted_collection = Enum.sort(collection)
91
- [
92
- Enum.at(sorted_collection, div(count, 2)),
93
- Enum.at(sorted_collection, div(count, 2) - 1)
94
- ]
95
- |> Math.Enum.mean
99
+ collection
100
+ |> Enum.sort()
101
+ |> Enum.slice((mid_point - 1)..mid_point)
102
+ |> Math.Enum.mean()
96
103
end
97
104
end
105
+
106
+ @doc """
107
+ Calculates the mode of a given collection of numbers.
108
+
109
+ Always returns a list. An empty input results in an empty list. Supports bimodal/multimodal collections by returning a list with multiple values.
110
+
111
+ ## Examples
112
+
113
+ iex> Math.Enum.mode [1, 2, 3, 4, 1]
114
+ [1]
115
+ iex> Math.Enum.mode [1, 2, 3, 2, 3]
116
+ [2, 3]
117
+ iex> Math.Enum.mode []
118
+ []
119
+ """
120
+ @spec mode(Enum.t()) :: Enum.t()
121
+ def mode(collection)
122
+
123
+ def mode(collection) do
124
+ collection
125
+ |> Enum.reduce(%{}, fn k, acc -> Map.update(acc, k, 0, &(&1 + 1)) end)
126
+ |> Enum.group_by(&elem(&1, 1), &elem(&1, 0))
127
+ |> Enum.max_by(&elem(&1, 0), fn -> {nil, []} end)
128
+ |> elem(1)
129
+ end
98
130
end
changed mix.exs
 
@@ -1,22 +1,30 @@
1
1
defmodule Math.Mixfile do
2
2
use Mix.Project
3
3
4
+ @source_url "https://github.com/folz/math"
5
+
4
6
def project do
5
- [app: :math,
6
- version: "0.3.1",
7
- elixir: "~> 1.2",
8
- description: description(),
9
- package: package(),
10
- deps: deps(),
11
- build_embedded: Mix.env == :prod,
12
- start_permanent: Mix.env == :prod]
7
+ [
8
+ app: :math,
9
+ version: "0.4.0",
10
+ elixir: "~> 1.2",
11
+ description: description(),
12
+ package: package(),
13
+ deps: deps(),
14
+ source_url: @source_url,
15
+ build_embedded: Mix.env() == :prod,
16
+ start_permanent: Mix.env() == :prod,
17
+ docs: docs()
18
+ ]
13
19
end
14
20
15
21
# Configuration for the OTP application
16
22
#
17
23
# Type "mix help compile.app" for more information
18
24
def application do
19
- [applications: [:logger]]
25
+ [
26
+ extra_applications: [:logger]
27
+ ]
20
28
end
21
29
22
30
defp description do
 
@@ -27,15 +35,26 @@ defmodule Math.Mixfile do
27
35
28
36
defp package do
29
37
[
38
+ name: :math,
39
+ files: ["lib", "mix.exs", "README*", "LICENSE"],
30
40
maintainers: ["Rodney Folz", "Wiebe-Marten Wijnja/Qqwy"],
31
41
licenses: ["Apache-2.0"],
32
- links: %{"GitHub": "https://github.com/folz/math"}
42
+ links: %{GitHub: @source_url}
33
43
]
34
44
end
35
45
36
46
defp deps do
37
47
[
38
- {:ex_doc, ">= 0.11.4", only: [:dev]}
48
+ {:credo, "~> 1.1.0", only: [:dev, :test], runtime: false},
49
+ {:ex_doc, ">= 0.11.4", only: [:docs]},
50
+ {:inch_ex, ">= 0.0.0", only: [:docs]},
51
+ ]
52
+ end
53
+
54
+ defp docs do
55
+ [
56
+ main: "readme",
57
+ extras: ["README.md"]
39
58
]
40
59
end
41
60
end