diff --git a/src/gleam_community/maths/float_list.gleam b/src/gleam_community/maths/float_list.gleam
index 860774b..455a40c 100644
--- a/src/gleam_community/maths/float_list.gleam
+++ b/src/gleam_community/maths/float_list.gleam
@@ -26,14 +26,14 @@
//// * **Distances, sums, and products**
//// * [`sum`](#sum)
//// * [`product`](#product)
+//// * [`cumulative_sum`](#cumulative_sum)
+//// * [`cumulative_product`](#cumulative_product)
//// * [`norm`](#norm)
//// * [`minkowski_distance`](#minkowski_distance)
//// * [`euclidean_distance`](#euclidean_distance)
//// * [`manhatten_distance`](#manhatten_distance)
-//// * [`cumulative_sum`](#cumulative_sum)
-//// * [`cumulative_product`](#cumulative_product)
//// * **Ranges and intervals**
-//// * [`arrange`](#arrange)
+//// * [`arange`](#arange)
//// * [`linear_space`](#linear_space)
//// * [`logarithmic_space`](#logarithmic_space)
//// * [`geometric_space`](#geometric_space)
@@ -252,7 +252,7 @@ pub fn euclidean_distance(
///
///
///
-/// Calculcate the Euclidean distance between two lists (representing vectors):
+/// Calculcate the Manhatten distance between two lists (representing vectors):
///
/// \\[
/// \sum_{i=1}^n \left|x_i - x_j \right|
@@ -271,11 +271,11 @@ pub fn euclidean_distance(
/// assert Ok(tol) = floatx.power(-10.0, -6.0)
///
/// // Empty lists returns 0.0
-/// float_list.manhatten_distance([], [], 1.0)
+/// float_list.manhatten_distance([], [])
/// |> should.equal(Ok(0.0))
///
/// // Differing lengths returns error
-/// float_list.manhatten_distance([], [1.0], 1.0)
+/// float_list.manhatten_distance([], [1.0])
/// |> should.be_error()
///
/// assert Ok(result) = float_list.manhatten_distance([0.0, 0.0], [1.0, 2.0])
@@ -516,17 +516,17 @@ pub fn geometric_space(
/// import gleam_community/maths/float_list
///
/// pub fn example () {
-/// float_list.arrange(1.0, 5.0, 1.0)
+/// float_list.arange(1.0, 5.0, 1.0)
/// |> should.equal([1.0, 2.0, 3.0, 4.0])
///
/// // No points returned since
/// // start smaller than stop and positive step
-/// float_list.arrange(5.0, 1.0, 1.0)
+/// float_list.arange(5.0, 1.0, 1.0)
/// |> should.equal([])
///
/// // Points returned since
/// // start smaller than stop but negative step
-/// float_list.arrange(5.0, 1.0, -1.0)
+/// float_list.arange(5.0, 1.0, -1.0)
/// |> should.equal([5.0, 4.0, 3.0, 2.0])
/// }
///
@@ -537,7 +537,7 @@ pub fn geometric_space(
///
///
///
-pub fn arrange(start: Float, stop: Float, step: Float) -> List(Float) {
+pub fn arange(start: Float, stop: Float, step: Float) -> List(Float) {
case start >=. stop && step >. 0.0 || start <=. stop && step <. 0.0 {
True -> []
False -> {
@@ -556,10 +556,6 @@ pub fn arrange(start: Float, stop: Float, step: Float) -> List(Float) {
}
}
-// fn do_arrange(start: Float, step: Float, direction: Float) -> Float {
-// case
-// }
-
///
///
/// Spot a typo? Open an issue!
@@ -629,15 +625,15 @@ pub fn sum(arr: List(Float)) -> Float {
/// import gleam_community/maths/float_list
///
/// pub fn example () {
-/// // An empty list returns an error
+/// // An empty list returns 0.0
/// []
/// |> float_list.sum()
-/// |> should.equal(0.)
+/// |> should.equal(0.0)
///
/// // Valid input returns a result
-/// [1., 2., 3.]
+/// [1.0, 2.0, 3.0]
/// |> float_list.product()
-/// |> should.equal(6.)
+/// |> should.equal(6.0)
/// }
///
///
@@ -652,7 +648,7 @@ pub fn product(arr: List(Float)) -> Float {
[] -> 0.0
_ ->
arr
- |> list.fold(0.0, fn(acc: Float, a: Float) -> Float { a *. acc })
+ |> list.fold(1.0, fn(acc: Float, a: Float) -> Float { a *. acc })
}
}
diff --git a/src/gleam_community/maths/int.gleam b/src/gleam_community/maths/int.gleam
index 8426686..a2ba8dd 100644
--- a/src/gleam_community/maths/int.gleam
+++ b/src/gleam_community/maths/int.gleam
@@ -30,12 +30,13 @@
//// * [`flip_sign`](#flipsign)
//// * **Misc. mathematical functions**
//// * [`minimum`](#min)
-//// * [`maxximum`](#max)
+//// * [`maximum`](#max)
//// * [`minmax`](#minmax)
//// * **Division functions**
//// * [`gcd`](#gcd)
//// * [`lcm`](#lcm)
//// * [`divisors`](#divisors)
+//// * [`proper_divisors`](#proper_divisors)
//// * **Combinatorial functions**
//// * [`combination`](#combination)
//// * [`factorial`](#factorial)
@@ -532,7 +533,7 @@ pub fn is_power(x: Int, y: Int) -> Bool {
///
///
///
-/// A function that tests whether a given integer value $$x \in \mathbb{Z}$$ is a perfect number. A number is perfect if it is equal to the sum of its proper positive divisors.
+/// A function that tests whether a given integer value $$n \in \mathbb{Z}$$ is a perfect number. A number is perfect if it is equal to the sum of its proper positive divisors.
///
///
/// Details
@@ -564,8 +565,17 @@ pub fn is_power(x: Int, y: Int) -> Bool {
///
///
///
-pub fn is_perfect(x: Int, y: Int) -> Bool {
- todo
+pub fn is_perfect(n: Int) -> Bool {
+ do_sum(proper_divisors(n)) == n
+}
+
+fn do_sum(arr: List(Int)) -> Int {
+ case arr {
+ [] -> 0
+ _ ->
+ arr
+ |> list.fold(0, fn(acc: Int, a: Int) -> Int { a + acc })
+ }
}
///
@@ -574,7 +584,46 @@ pub fn is_perfect(x: Int, y: Int) -> Bool {
///
///
///
-/// The function returns all the positive divisors of an integer.
+/// The function returns all the positive divisors of an integer, excluding the number iteself.
+///
+///
+/// Example:
+///
+/// import gleeunit/should
+/// import gleam_community/maths/int as intx
+///
+/// pub fn example() {
+/// intx.proper_divisors(4)
+/// |> should.equal([1, 2])
+///
+/// intx.proper_divisors(6)
+/// |> should.equal([1, 2, 3])
+///
+/// intx.proper_divisors(13)
+/// |> should.equal([1])
+///
+/// }
+///
+///
+///
+///
+pub fn proper_divisors(n: Int) -> List(Int) {
+ let divisors: List(Int) = find_divisors(n)
+ divisors
+ |> list.take(list.length(divisors) - 1)
+}
+
+///
+///
+/// The function returns all the positive divisors of an integer, including the number iteself.
///
///
/// Example:
@@ -588,6 +637,9 @@ pub fn is_perfect(x: Int, y: Int) -> Bool {
///
/// intx.divisors(6)
/// |> should.equal([1, 2, 3, 6])
+///
+/// intx.proper_divisors(13)
+/// |> should.equal([1, 13])
/// }
///
///
@@ -597,8 +649,26 @@ pub fn is_perfect(x: Int, y: Int) -> Bool {
///
///
///
-pub fn divisors(x: Int) -> List(Int) {
- todo
+pub fn divisors(n: Int) -> List(Int) {
+ find_divisors(n)
+}
+
+pub fn find_divisors(n: Int) -> List(Int) {
+ let nabs: Float = float.absolute_value(to_float(n))
+ assert Ok(sqrt_result) = floatx.square_root(nabs)
+ let max: Int = floatx.to_int(sqrt_result) + 1
+ list.range(2, max)
+ |> list.fold(
+ [1, n],
+ fn(acc: List(Int), i: Int) -> List(Int) {
+ case n % i == 0 {
+ True -> [i, n / i, ..acc]
+ False -> acc
+ }
+ },
+ )
+ |> list.unique()
+ |> list.sort(int.compare)
}
///
diff --git a/src/gleam_community/maths/int_list.gleam b/src/gleam_community/maths/int_list.gleam
index c4439af..a1701d3 100644
--- a/src/gleam_community/maths/int_list.gleam
+++ b/src/gleam_community/maths/int_list.gleam
@@ -26,9 +26,9 @@
//// * **Distances, sums and products**
//// * [`sum`](#sum)
//// * [`product`](#product)
-//// * [`norm`](#norm)
//// * [`cumulative_sum`](#cumulative_sum)
//// * [`cumulative_product`](#cumulative_product)
+//// * [`manhatten_distance`](#manhatten_distance)
//// * **Misc. mathematical functions**
//// * [`maximum`](#maximum)
//// * [`minimum`](#minimum)
@@ -42,6 +42,164 @@ import gleam/float
import gleam/pair
import gleam_community/maths/int as intx
+///
+///
+/// Calculcate the Manhatten distance between two lists (representing vectors):
+///
+/// \\[
+/// \sum_{i=1}^n \left|x_i - x_j \right|
+/// \\]
+///
+/// In the formula, $$n$$ is the length of the two lists and $$x_i, y_i$$ are the values in the respective input lists indexed by $$i, j$$.
+///
+///
+/// Example:
+///
+/// import gleeunit/should
+/// import gleam_community/maths/float as floatx
+/// import gleam_community/maths/float_list
+///
+/// pub fn example () {
+/// // Empty lists returns 0
+/// float_list.manhatten_distance([], [])
+/// |> should.equal(Ok(0.0))
+///
+/// // Differing lengths returns error
+/// float_list.manhatten_distance([], [1])
+/// |> should.be_error()
+///
+/// assert Ok(result) = int_list.manhatten_distance([0, 0], [1, 2])
+/// result
+/// |> should.equal(3)
+/// }
+///
+///
+///
+///
+pub fn manhatten_distance(
+ xarr: List(Int),
+ yarr: List(Int),
+) -> Result(Int, String) {
+ let xlen: Int = list.length(xarr)
+ let ylen: Int = list.length(yarr)
+ case xlen == ylen {
+ False ->
+ "Invalid input argument: length(xarr) != length(yarr). Valid input is when length(xarr) == length(yarr)."
+ |> Error
+ True ->
+ list.zip(xarr, yarr)
+ |> list.map(fn(tuple: #(Int, Int)) -> Int {
+ int.absolute_value(pair.first(tuple) - pair.second(tuple))
+ })
+ |> sum()
+ |> Ok
+ }
+}
+
+///
+///
+/// Calculcate the sum of the elements in a list:
+///
+/// \\[
+/// \sum_{i=1}^n x_i
+/// \\]
+///
+/// In the formula, $$n$$ is the length of the list and $$x_i$$ is the value in the input list indexed by $$i$$.
+///
+///
+/// Example:
+///
+/// import gleeunit/should
+/// import gleam_community/maths/float_list
+///
+/// pub fn example () {
+/// // An empty list returns 0
+/// []
+/// |> float_list.sum()
+/// |> should.equal(0)
+///
+/// // Valid input returns a result
+/// [1, 2, 3]
+/// |> float_list.sum()
+/// |> should.equal(6)
+/// }
+///
+///
+///
+///
+pub fn sum(arr: List(Int)) -> Int {
+ case arr {
+ [] -> 0
+ _ ->
+ arr
+ |> list.fold(0, fn(acc: Int, a: Int) -> Int { a + acc })
+ }
+}
+
+///
+///
+/// Calculcate the product of the elements in a list:
+///
+/// \\[
+/// \prod_{i=1}^n x_i
+/// \\]
+///
+/// In the formula, $$n$$ is the length of the list and $$x_i$$ is the value in the input list indexed by $$i$$.
+///
+///
+/// Example:
+///
+/// import gleeunit/should
+/// import gleam_community/maths/float_list
+///
+/// pub fn example () {
+/// // An empty list returns an error
+/// []
+/// |> float_list.sum()
+/// |> should.equal(0.)
+///
+/// // Valid input returns a result
+/// [1., 2., 3.]
+/// |> float_list.product()
+/// |> should.equal(6.)
+/// }
+///
+///
+///
+///
+pub fn product(arr: List(Int)) -> Int {
+ case arr {
+ [] -> 0
+ _ ->
+ arr
+ |> list.fold(1, fn(acc: Int, a: Int) -> Int { a * acc })
+ }
+}
+
///
///
/// Spot a typo? Open an issue!
diff --git a/test/gleam/gleam_community_maths_float_list_test.gleam b/test/gleam/gleam_community_maths_float_list_test.gleam
index 60c0401..6421afd 100644
--- a/test/gleam/gleam_community_maths_float_list_test.gleam
+++ b/test/gleam/gleam_community_maths_float_list_test.gleam
@@ -88,7 +88,7 @@ pub fn float_list_minkowski_test() {
float_list.minkowski_distance([], [], 1.0)
|> should.equal(Ok(0.0))
- // Differing lenghths returns error
+ // Differing lengths returns error
float_list.minkowski_distance([], [1.0], 1.0)
|> should.be_error()
@@ -141,7 +141,7 @@ pub fn float_list_euclidean_test() {
float_list.euclidean_distance([], [])
|> should.equal(Ok(0.0))
- // Differing lenghths returns error
+ // Differing lengths returns error
float_list.euclidean_distance([], [1.0])
|> should.be_error()
@@ -159,7 +159,7 @@ pub fn float_list_manhatten_test() {
float_list.manhatten_distance([], [])
|> should.equal(Ok(0.0))
- // Differing lenghths returns error
+ // Differing lengths returns error
float_list.manhatten_distance([], [1.0])
|> should.be_error()
@@ -353,35 +353,35 @@ pub fn float_list_geometric_space_test() {
|> should.be_error()
}
-pub fn float_list_arrange_test() {
+pub fn float_list_arange_test() {
// Positive start, stop, step
- float_list.arrange(1.0, 5.0, 1.0)
+ float_list.arange(1.0, 5.0, 1.0)
|> should.equal([1.0, 2.0, 3.0, 4.0])
- float_list.arrange(1.0, 5.0, 0.5)
+ float_list.arange(1.0, 5.0, 0.5)
|> should.equal([1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5])
- float_list.arrange(1.0, 2.0, 0.25)
+ float_list.arange(1.0, 2.0, 0.25)
|> should.equal([1.0, 1.25, 1.5, 1.75])
// Reverse (switch start/stop largest/smallest value)
- float_list.arrange(5.0, 1.0, 1.0)
+ float_list.arange(5.0, 1.0, 1.0)
|> should.equal([])
// Reverse negative step
- float_list.arrange(5.0, 1.0, -1.0)
+ float_list.arange(5.0, 1.0, -1.0)
|> should.equal([5.0, 4.0, 3.0, 2.0])
// Positive start, negative stop, step
- float_list.arrange(5.0, -1.0, -1.0)
+ float_list.arange(5.0, -1.0, -1.0)
|> should.equal([5.0, 4.0, 3.0, 2.0, 1.0, 0.0])
// Negative start, stop, step
- float_list.arrange(-5.0, -1.0, -1.0)
+ float_list.arange(-5.0, -1.0, -1.0)
|> should.equal([])
// Negative start, stop, positive step
- float_list.arrange(-5.0, -1.0, 1.0)
+ float_list.arange(-5.0, -1.0, 1.0)
|> should.equal([-5.0, -4.0, -3.0, -2.0])
}
@@ -445,6 +445,22 @@ pub fn float_list_extrema_test() {
|> should.equal(Ok(#(1.0, 4.0)))
}
+pub fn float_list_sum_test() {
+ // An empty list returns 0
+ []
+ |> float_list.sum()
+ |> should.equal(0.0)
+
+ // Valid input returns a result
+ [1.0, 2.0, 3.0]
+ |> float_list.sum()
+ |> should.equal(6.0)
+
+ [-2.0, 4.0, 6.0]
+ |> float_list.sum()
+ |> should.equal(8.0)
+}
+
pub fn float_list_cumulative_sum_test() {
// An empty lists returns an empty list
[]
@@ -455,6 +471,26 @@ pub fn float_list_cumulative_sum_test() {
[1.0, 2.0, 3.0]
|> float_list.cumulative_sum()
|> should.equal([1.0, 3.0, 6.0])
+
+ [-2.0, 4.0, 6.0]
+ |> float_list.cumulative_sum()
+ |> should.equal([-2.0, 2.0, 8.0])
+}
+
+pub fn float_list_product_test() {
+ // An empty list returns 0
+ []
+ |> float_list.product()
+ |> should.equal(0.0)
+
+ // Valid input returns a result
+ [1.0, 2.0, 3.0]
+ |> float_list.product()
+ |> should.equal(6.0)
+
+ [-2.0, 4.0, 6.0]
+ |> float_list.product()
+ |> should.equal(-48.0)
}
pub fn float_list_cumulative_product_test() {
@@ -467,4 +503,8 @@ pub fn float_list_cumulative_product_test() {
[1.0, 2.0, 3.0]
|> float_list.cumumlative_product()
|> should.equal([1.0, 2.0, 6.0])
+
+ [-2.0, 4.0, 6.0]
+ |> float_list.cumumlative_product()
+ |> should.equal([-2.0, -8.0, -48.0])
}
diff --git a/test/gleam/gleam_community_maths_int_list_test.gleam b/test/gleam/gleam_community_maths_int_list_test.gleam
index 1be0e4e..a0ec5d6 100644
--- a/test/gleam/gleam_community_maths_int_list_test.gleam
+++ b/test/gleam/gleam_community_maths_int_list_test.gleam
@@ -69,6 +69,22 @@ pub fn int_list_extrema_test() {
|> should.equal(Ok(#(1, 4)))
}
+pub fn int_list_sum_test() {
+ // An empty list returns 0
+ []
+ |> int_list.sum()
+ |> should.equal(0)
+
+ // Valid input returns a result
+ [1, 2, 3]
+ |> int_list.sum()
+ |> should.equal(6)
+
+ [-2, 4, 6]
+ |> int_list.sum()
+ |> should.equal(8)
+}
+
pub fn int_list_cumulative_sum_test() {
// An empty lists returns an empty list
[]
@@ -79,6 +95,26 @@ pub fn int_list_cumulative_sum_test() {
[1, 2, 3]
|> int_list.cumulative_sum()
|> should.equal([1, 3, 6])
+
+ [-2, 4, 6]
+ |> int_list.cumulative_sum()
+ |> should.equal([-2, 2, 8])
+}
+
+pub fn int_list_product_test() {
+ // An empty list returns 0
+ []
+ |> int_list.product()
+ |> should.equal(0)
+
+ // Valid input returns a result
+ [1, 2, 3]
+ |> int_list.product()
+ |> should.equal(6)
+
+ [-2, 4, 6]
+ |> int_list.product()
+ |> should.equal(-48)
}
pub fn int_list_cumulative_product_test() {
@@ -91,4 +127,22 @@ pub fn int_list_cumulative_product_test() {
[1, 2, 3]
|> int_list.cumumlative_product()
|> should.equal([1, 2, 6])
+
+ [-2, 4, 6]
+ |> int_list.cumumlative_product()
+ |> should.equal([-2, -8, -48])
+}
+
+pub fn int_list_manhatten_test() {
+ // Empty lists returns 0
+ int_list.manhatten_distance([], [])
+ |> should.equal(Ok(0))
+
+ // Differing lengths returns error
+ int_list.manhatten_distance([], [1])
+ |> should.be_error()
+
+ assert Ok(result) = int_list.manhatten_distance([0, 0], [1, 2])
+ result
+ |> should.equal(3)
}
diff --git a/test/gleam/gleam_community_maths_int_test.gleam b/test/gleam/gleam_community_maths_int_test.gleam
index 26d790a..af4809f 100644
--- a/test/gleam/gleam_community_maths_int_test.gleam
+++ b/test/gleam/gleam_community_maths_int_test.gleam
@@ -277,3 +277,51 @@ pub fn int_to_float_test() {
intx.to_float(1)
|> should.equal(1.0)
}
+
+pub fn int_proper_divisors_test() {
+ intx.proper_divisors(2)
+ |> should.equal([1])
+
+ intx.proper_divisors(6)
+ |> io.debug()
+ |> should.equal([1, 2, 3])
+ intx.proper_divisors(13)
+ |> should.equal([1])
+
+ intx.proper_divisors(18)
+ |> should.equal([1, 2, 3, 6, 9])
+}
+
+pub fn int_divisors_test() {
+ intx.divisors(2)
+ |> should.equal([1, 2])
+
+ intx.divisors(6)
+ |> should.equal([1, 2, 3, 6])
+
+ intx.divisors(13)
+ |> should.equal([1, 13])
+
+ intx.divisors(18)
+ |> should.equal([1, 2, 3, 6, 9, 18])
+}
+
+pub fn int_is_perfect_test() {
+ intx.is_perfect(6)
+ |> should.equal(True)
+
+ intx.is_perfect(28)
+ |> should.equal(True)
+
+ intx.is_perfect(496)
+ |> should.equal(True)
+
+ intx.is_perfect(1)
+ |> should.equal(False)
+
+ intx.is_perfect(3)
+ |> should.equal(False)
+
+ intx.is_perfect(13)
+ |> should.equal(False)
+}