Skip to content

Commit 42a00d7

Browse files
author
i1e0
authored
Improve math functions and binary search (#18)
1 parent 7213a0b commit 42a00d7

File tree

14 files changed

+323
-66
lines changed

14 files changed

+323
-66
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace Algorithms.Tests.Math
2+
3+
open Microsoft.VisualStudio.TestTools.UnitTesting
4+
open Algorithms.Math
5+
6+
[<TestClass>]
7+
type AbsMaxTests() =
8+
9+
[<TestMethod>]
10+
member this.Test() =
11+
Assert.AreEqual(-3, AbsMax.absMax [ -1; 1; 2; -2; -3; 3 ])
12+
Assert.AreEqual(3, AbsMax.absMax [ 1; -1; 2; -2; 3; -3 ])
13+
Assert.AreEqual(-1, AbsMax.absMax [ 0; -1; 0 ])
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace Algorithms.Tests.Math
2+
3+
open Microsoft.VisualStudio.TestTools.UnitTesting
4+
open Algorithms.Math
5+
6+
[<TestClass>]
7+
type AbsMinTests() =
8+
9+
[<TestMethod>]
10+
member this.Test() =
11+
Assert.AreEqual(-1, AbsMin.absMin [ -1; 1; 2; -2; -3; 3 ])
12+
Assert.AreEqual(1, AbsMin.absMin [ 1; -1; 2; -2; 3; -3 ])
13+
Assert.AreEqual(0, AbsMin.absMin [ 0; -1; 0 ])

Algorithms.Tests/Math/AbsTests.fs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace Algorithms.Tests.Math
2+
3+
open Microsoft.VisualStudio.TestTools.UnitTesting
4+
open Algorithms.Math
5+
6+
[<TestClass>]
7+
type AbsTests() =
8+
9+
[<TestMethod>]
10+
[<DataRow(-10, 10)>]
11+
[<DataRow(-1, 1)>]
12+
[<DataRow(0, 0)>]
13+
[<DataRow(1, 1)>]
14+
[<DataRow(10, 10)>]
15+
member this.Test(input: int, expected: int) =
16+
let actual = Abs.absVal input
17+
Assert.AreEqual(expected, actual)

Algorithms.Tests/Math/FactorialTests.fs

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,56 @@ open Microsoft.VisualStudio.TestTools.UnitTesting
44
open Algorithms.Math
55

66
[<TestClass>]
7-
type FactorialTests () =
8-
7+
type FactorialTests() =
8+
99
[<TestMethod>]
10+
[<DataRow(0, 1)>]
1011
[<DataRow(1, 1)>]
1112
[<DataRow(2, 2)>]
1213
[<DataRow(3, 6)>]
1314
[<DataRow(5, 120)>]
1415
[<DataRow(8, 40320)>]
1516
[<DataRow(10, 3628800)>]
16-
member this.FactorialOf (num: int, expected: int) =
17-
let actual = Factorial.CalculateFactorial num
18-
Assert.AreEqual(expected, actual)
17+
[<DataRow(12, 479001600)>]
18+
member this.ValidInt(num: int, expected: int) =
19+
seq {
20+
Factorial.byFoldFunction
21+
Factorial.byReduceFunction
22+
Factorial.byRecursion
23+
Factorial.byTailRecursion
24+
Factorial.byTailRecursionGeneric
25+
}
26+
|> Seq.iter (fun func ->
27+
let actual = func num
28+
Assert.AreEqual(expected, actual))
29+
30+
[<TestMethod>]
31+
[<DataRow(-1)>]
32+
member this.InvalidInt(num: int) =
33+
seq {
34+
Factorial.byFoldFunction
35+
Factorial.byReduceFunction
36+
Factorial.byRecursion
37+
Factorial.byTailRecursion
38+
Factorial.byTailRecursionGeneric
39+
}
40+
|> Seq.iter (fun func ->
41+
let action =
42+
new System.Action(fun () -> func num |> ignore)
43+
44+
Assert.ThrowsException(action) |> ignore)
45+
46+
[<TestMethod>]
47+
member this.Generic() =
48+
Assert.AreEqual(479001600, Factorial.byTailRecursionGeneric 12)
49+
Assert.AreEqual(479001600u, Factorial.byTailRecursionGeneric 12u)
50+
Assert.AreEqual(479001600.f, Factorial.byTailRecursionGeneric 12.f)
51+
Assert.AreEqual(2432902008176640000L, Factorial.byTailRecursionGeneric 20L)
52+
Assert.AreEqual(2432902008176640000UL, Factorial.byTailRecursionGeneric 20UL)
53+
Assert.AreEqual(2432902008176640000., Factorial.byTailRecursionGeneric 20.)
54+
Assert.AreEqual(10888869450418352160768000000M, Factorial.byTailRecursionGeneric 27M)
55+
56+
Assert.AreEqual(
57+
30414093201713378043612608166064768844377641568960512000000000000I,
58+
Factorial.byTailRecursionGeneric 50I
59+
)

Algorithms.Tests/Math/PerfectNumbersTests.fs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ open Microsoft.VisualStudio.TestTools.UnitTesting
44
open Algorithms.Math
55

66
[<TestClass>]
7-
type PerfectNumbersTests () =
8-
7+
type PerfectNumbersTests() =
8+
99
[<TestMethod>]
1010
[<DataRow(-1, false)>]
1111
[<DataRow(0, false)>]
@@ -22,6 +22,6 @@ type PerfectNumbersTests () =
2222
[<DataRow(8128, true)>]
2323
[<DataRow(33550336, true)>]
2424
[<DataRow(33550337, false)>]
25-
member this.IsPerfect (n: int, expected: bool) =
26-
let actual = Perfect_Numbers.IsPerfect n
27-
Assert.AreEqual(expected, actual)
25+
member this.Test(n: int, expected: bool) =
26+
let actual = PerfectNumbers.isPerfect n
27+
Assert.AreEqual(expected, actual)

Algorithms.Tests/Math/PowerTests.fs

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ open Microsoft.VisualStudio.TestTools.UnitTesting
44
open Algorithms.Math
55

66
[<TestClass>]
7-
type PowerTests () =
8-
7+
type PowerTests() =
8+
99
[<TestMethod>]
10+
[<DataRow(0, 100, 0)>]
1011
[<DataRow(2, 2, 4)>]
1112
[<DataRow(2, 3, 8)>]
1213
[<DataRow(2, 4, 16)>]
@@ -17,6 +18,50 @@ type PowerTests () =
1718
[<DataRow(10, 4, 10000)>]
1819
[<DataRow(1, 2, 1)>]
1920
[<DataRow(1, 50, 1)>]
20-
member this.PowerOf (num: int, pow: int, expected: int) =
21-
let actual = Power.Pow num pow
22-
Assert.AreEqual(expected, actual)
21+
member this.FoldFunction_Valid(num: int, pow: int, expected: int) =
22+
let actual = Power.byFoldFunction num pow
23+
Assert.AreEqual(expected, actual)
24+
25+
[<TestMethod>]
26+
[<DataRow(-2, -2, 0)>]
27+
[<DataRow(-2, -1, 0)>]
28+
[<DataRow(-2, 0, 1)>]
29+
[<DataRow(-2, 1, -2)>]
30+
[<DataRow(-2, 2, 4)>]
31+
[<DataRow(-2, 3, -8)>]
32+
[<DataRow(-1, -3, -1)>]
33+
[<DataRow(-1, -2, 1)>]
34+
[<DataRow(-1, -1, -1)>]
35+
[<DataRow(-1, 0, 1)>]
36+
[<DataRow(-1, 1, -1)>]
37+
[<DataRow(-1, 2, 1)>]
38+
[<DataRow(-1, 3, -1)>]
39+
[<DataRow(0, 0, 1)>]
40+
[<DataRow(0, 1, 0)>]
41+
[<DataRow(0, 2, 0)>]
42+
[<DataRow(1, -2, 1)>]
43+
[<DataRow(1, -1, 1)>]
44+
[<DataRow(1, 0, 1)>]
45+
[<DataRow(1, 1, 1)>]
46+
[<DataRow(1, 2, 1)>]
47+
[<DataRow(2, 2, 4)>]
48+
[<DataRow(2, 3, 8)>]
49+
[<DataRow(2, 4, 16)>]
50+
[<DataRow(2, 8, 256)>]
51+
[<DataRow(2, 16, 65536)>]
52+
[<DataRow(3, 5, 243)>]
53+
[<DataRow(5, 3, 125)>]
54+
[<DataRow(10, 4, 10000)>]
55+
member this.ByRecursion_Valid(num: int, pow: int, expected: int) =
56+
let actual = Power.byRecursion num pow
57+
Assert.AreEqual(expected, actual)
58+
59+
[<TestMethod>]
60+
[<DataRow(0, -1)>]
61+
[<DataRow(0, -2)>]
62+
member this.ByRecursion_Invalid(num: int, pow: int) =
63+
let action =
64+
new System.Action(fun () -> Power.byRecursion num pow |> ignore)
65+
66+
Assert.ThrowsException<System.DivideByZeroException>(action)
67+
|> ignore
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
namespace Algorithms.Tests.Math
2+
3+
open Microsoft.VisualStudio.TestTools.UnitTesting
4+
open Algorithms.Math
5+
6+
[<TestClass>]
7+
type PrimeTests() =
8+
9+
[<TestMethod>]
10+
[<DataRow(-3, false)>]
11+
[<DataRow(-2, false)>]
12+
[<DataRow(-1, false)>]
13+
[<DataRow(0, false)>]
14+
[<DataRow(1, false)>]
15+
[<DataRow(2, true)>]
16+
[<DataRow(49, false)>]
17+
[<DataRow(50, false)>]
18+
[<DataRow(998244353, true)>]
19+
[<DataRow(1000000007, true)>]
20+
member this.IsPrime(input: int, expected: bool) =
21+
let actual = Prime.isPrime input
22+
Assert.AreEqual(expected, actual)
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
namespace Algorithms.Tests.Search
2+
3+
open Microsoft.VisualStudio.TestTools.UnitTesting
4+
open Algorithms.Search
5+
6+
[<TestClass>]
7+
type BinarySearchTests() =
8+
let data0 =
9+
[| -2147483468
10+
-10
11+
-2
12+
-1
13+
0
14+
1
15+
2
16+
10
17+
20
18+
20
19+
2147483467 |]
20+
21+
[<TestMethod>]
22+
[<DataRow(-2147483468, 0)>]
23+
[<DataRow(-10, 1)>]
24+
[<DataRow(-2, 2)>]
25+
[<DataRow(-1, 3)>]
26+
[<DataRow(0, 4)>]
27+
[<DataRow(1, 5)>]
28+
[<DataRow(2, 6)>]
29+
[<DataRow(10, 7)>]
30+
[<DataRow(2147483467, 10)>]
31+
member this.Data0_Exists(num: int, expected: int) =
32+
let actual = BinarySearch.findIndex num data0
33+
Assert.AreEqual(expected, actual)
34+
35+
[<TestMethod>]
36+
[<DataRow(20)>]
37+
member this.Data0_Duplicates(num: int) =
38+
let actual = BinarySearch.findIndex num data0
39+
Assert.IsTrue(actual = 8 || actual = 9)
40+
41+
[<TestMethod>]
42+
[<DataRow(5, -1)>]
43+
member this.Data0_None(num: int, expected: int) =
44+
let actual = BinarySearch.findIndex num data0
45+
Assert.AreEqual(expected, actual)

Algorithms/Math/Factorial.fs

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,48 @@
11
namespace Algorithms.Math
22

33
module Factorial =
4-
let CalculateFactorial num =
5-
if (num < 0)
6-
then failwith "No Factorial for negative numbers"
7-
else [1..num] |> Seq.fold (fun acc n -> acc * n) 1
4+
/// Calculates factorial. Time complexity: O(n)
5+
let byFoldFunction n =
6+
if n < 0 then
7+
failwith "No factorial for negative numbers"
8+
else
9+
{ 1 .. n } |> Seq.fold (fun acc n -> acc * n) 1
10+
11+
/// Calculates factorial. Time complexity: O(n)
12+
let byReduceFunction n =
13+
match n with
14+
| n when n < 0 -> failwith "No factorial for negative numbers"
15+
| 0 -> 1
16+
| n -> { 1 .. n } |> Seq.reduce (*)
17+
18+
/// Calculates factorial. Time complexity: O(n)
19+
let rec byRecursion n =
20+
match sign n with
21+
| -1 -> failwith "No factorial for negative numbers"
22+
| 0 -> 1
23+
| _ -> n * byRecursion (n - 1)
24+
25+
/// Calculates factorial. Time complexity: O(n)
26+
let byTailRecursion n =
27+
let rec inner n prod =
28+
match n with
29+
| 0 -> prod
30+
| _ -> inner (n - 1) (prod * n)
31+
32+
match n with
33+
| n when n < 0 -> failwith "No factorial for negative numbers"
34+
| _ -> inner n 1
35+
36+
/// Calculates factorial. Time complexity: O(n)
37+
let inline byTailRecursionGeneric n =
38+
let gen0 = LanguagePrimitives.GenericZero
39+
let gen1 = LanguagePrimitives.GenericOne
40+
41+
let rec inner n prod =
42+
match n with
43+
| n when n = gen0 -> prod
44+
| _ -> inner (n - gen1) (prod * n)
45+
46+
match n with
47+
| n when n < gen0 -> failwith "No factorial for negative numbers"
48+
| _ -> inner n gen1

Algorithms/Math/PerfectNumbers.fs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace Algorithms.Math
2+
3+
module PerfectNumbers =
4+
/// Check if a number is perfect. Time complexity: O(√n)
5+
let isPerfect n =
6+
match n with
7+
| n when n <= 0 -> false
8+
| n ->
9+
{ 1 .. n - 1 }
10+
|> Seq.takeWhile (fun i -> i * i <= n)
11+
|> Seq.filter ((%) n >> (=) 0)
12+
|> Seq.fold (fun acc i -> acc + i + n / i) 0
13+
|> (=) (2 * n)

0 commit comments

Comments
 (0)