From d277ff078001304352aac27ddebc425be05568bb Mon Sep 17 00:00:00 2001 From: i1e0 <96235137+i1e0@users.noreply.github.com> Date: Wed, 5 Jan 2022 23:25:17 +0900 Subject: [PATCH 1/8] Update BinarySearch.fs --- Algorithms/Search/BinarySearch.fs | 49 +++++++++++-------------------- 1 file changed, 17 insertions(+), 32 deletions(-) diff --git a/Algorithms/Search/BinarySearch.fs b/Algorithms/Search/BinarySearch.fs index b898582..e34b64e 100644 --- a/Algorithms/Search/BinarySearch.fs +++ b/Algorithms/Search/BinarySearch.fs @@ -1,35 +1,20 @@ namespace Algorithms.Search -open System - module BinarySearch = - let rec byRecursion (sortedData: IComparable [], item: int, left: int, right: int) = - - let middle = left + (right - left) / 2 - - match sortedData.[middle] with - | s when s.CompareTo(sortedData.[middle]) > item -> byRecursion (sortedData, item, left, middle - 1) - | s when s.CompareTo(sortedData.[middle]) < item -> byRecursion (sortedData, item, left, middle + 1) - | _ -> middle - - /// - /// Finds index of item in array that equals to item searched for, - /// time complexity: O(log(n)), - /// space complexity: O(1), - /// where n - array size. - /// - /// Sorted array to search in. - /// Item to search for. - /// Index of item that equals to item searched for or -1 if none found. - let rec findIndex (sortedData: IComparable [], item: int) = - - let left = 0 - let right = sortedData.Length - 1 - - let middle = left + (right - left) / 2 - let currentItem = sortedData.[middle] - - match currentItem with - | c when c.CompareTo(sortedData.[middle]) > item -> findIndex (sortedData, item) - | c when c.CompareTo(sortedData.[middle]) < item -> findIndex (sortedData, item) - | _ -> item + /// Search the target item in a sorted array. + /// Returns -1 when the target is not found. + /// Time complexity: O(log(sortedData.Length))) + let findIndex target sortedData = + let rec search l r = + let count = r - l + let mid = (l + r) / 2 + let midItem = Array.item mid sortedData + + match count <= 1, compare midItem target with + | _, 0 -> mid + | true, _ -> -1 + | false, -1 -> search mid r + | false, 1 -> search l mid + | _ -> exn () |> raise + + search 0 (Array.length sortedData + 1) From 7e35a092b2910c9505ac5532b14b2976a950bd08 Mon Sep 17 00:00:00 2001 From: i1e0 <96235137+i1e0@users.noreply.github.com> Date: Wed, 5 Jan 2022 23:26:17 +0900 Subject: [PATCH 2/8] Add BinarySearchTest.fs --- Algorithms.Tests/Search/BinarySearchTests.fs | 45 ++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 Algorithms.Tests/Search/BinarySearchTests.fs diff --git a/Algorithms.Tests/Search/BinarySearchTests.fs b/Algorithms.Tests/Search/BinarySearchTests.fs new file mode 100644 index 0000000..da999e2 --- /dev/null +++ b/Algorithms.Tests/Search/BinarySearchTests.fs @@ -0,0 +1,45 @@ +namespace Algorithms.Tests.Search + +open Microsoft.VisualStudio.TestTools.UnitTesting +open Algorithms.Search + +[] +type BinarySearchTests() = + let data0 = + [| -2147483468 + -10 + -2 + -1 + 0 + 1 + 2 + 10 + 20 + 20 + 2147483467 |] + + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + member this.Data0_Exists(num: int, expected: int) = + let actual = BinarySearch.findIndex num data0 + Assert.AreEqual(expected, actual) + + [] + [] + member this.Data0_Duplicates(num: int) = + let actual = BinarySearch.findIndex num data0 + Assert.IsTrue(actual = 8 || actual = 9) + + [] + [] + member this.Data0_None(num: int, expected: int) = + let actual = BinarySearch.findIndex num data0 + Assert.AreEqual(expected, actual) From 84154909ebd143935fc0390ce296da4bc7532333 Mon Sep 17 00:00:00 2001 From: i1e0 <96235137+i1e0@users.noreply.github.com> Date: Wed, 5 Jan 2022 23:32:27 +0900 Subject: [PATCH 3/8] Add some functions to Factorial.fs --- Algorithms/Math/Factorial.fs | 49 +++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/Algorithms/Math/Factorial.fs b/Algorithms/Math/Factorial.fs index 458b98d..455eb40 100644 --- a/Algorithms/Math/Factorial.fs +++ b/Algorithms/Math/Factorial.fs @@ -1,7 +1,48 @@ namespace Algorithms.Math module Factorial = - let CalculateFactorial num = - if (num < 0) - then failwith "No Factorial for negative numbers" - else [1..num] |> Seq.fold (fun acc n -> acc * n) 1 \ No newline at end of file + /// Calculates factorial. Time complexity: O(n) + let byFoldFunction n = + if n < 0 then + failwith "No factorial for negative numbers" + else + { 1 .. n } |> Seq.fold (fun acc n -> acc * n) 1 + + /// Calculates factorial. Time complexity: O(n) + let byReduceFunction n = + match n with + | n when n < 0 -> failwith "No factorial for negative numbers" + | 0 -> 1 + | n -> { 1 .. n } |> Seq.reduce (*) + + /// Calculates factorial. Time complexity: O(n) + let rec byRecursion n = + match sign n with + | -1 -> failwith "No factorial for negative numbers" + | 0 -> 1 + | _ -> n * byRecursion (n - 1) + + /// Calculates factorial. Time complexity: O(n) + let byTailRecursion n = + let rec inner n prod = + match n with + | 0 -> prod + | _ -> inner (n - 1) (prod * n) + + match n with + | n when n < 0 -> failwith "No factorial for negative numbers" + | _ -> inner n 1 + + /// Calculates factorial. Time complexity: O(n) + let inline byTailRecursionGeneric n = + let gen0 = LanguagePrimitives.GenericZero + let gen1 = LanguagePrimitives.GenericOne + + let rec inner n prod = + match n with + | n when n = gen0 -> prod + | _ -> inner (n - gen1) (prod * n) + + match n with + | n when n < gen0 -> failwith "No factorial for negative numbers" + | _ -> inner n gen1 From 23d655bfd9bbd7d67f308e625d977e838b682d88 Mon Sep 17 00:00:00 2001 From: i1e0 <96235137+i1e0@users.noreply.github.com> Date: Wed, 5 Jan 2022 23:33:23 +0900 Subject: [PATCH 4/8] Increase test cases in FactorialTests.fs --- Algorithms.Tests/Math/FactorialTests.fs | 51 ++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/Algorithms.Tests/Math/FactorialTests.fs b/Algorithms.Tests/Math/FactorialTests.fs index 5cd15a9..6e3fb23 100644 --- a/Algorithms.Tests/Math/FactorialTests.fs +++ b/Algorithms.Tests/Math/FactorialTests.fs @@ -4,15 +4,56 @@ open Microsoft.VisualStudio.TestTools.UnitTesting open Algorithms.Math [] -type FactorialTests () = - +type FactorialTests() = + [] + [] [] [] [] [] [] [] - member this.FactorialOf (num: int, expected: int) = - let actual = Factorial.CalculateFactorial num - Assert.AreEqual(expected, actual) \ No newline at end of file + [] + member this.ValidInt(num: int, expected: int) = + seq { + Factorial.byFoldFunction + Factorial.byReduceFunction + Factorial.byRecursion + Factorial.byTailRecursion + Factorial.byTailRecursionGeneric + } + |> Seq.iter (fun func -> + let actual = func num + Assert.AreEqual(expected, actual)) + + [] + [] + member this.InvalidInt(num: int) = + seq { + Factorial.byFoldFunction + Factorial.byReduceFunction + Factorial.byRecursion + Factorial.byTailRecursion + Factorial.byTailRecursionGeneric + } + |> Seq.iter (fun func -> + let action = + new System.Action(fun () -> func num |> ignore) + + Assert.ThrowsException(action) |> ignore) + + [] + member this.Generic() = + Assert.AreEqual(479001600, Factorial.byTailRecursionGeneric 12) + Assert.AreEqual(479001600u, Factorial.byTailRecursionGeneric 12u) + Assert.AreEqual(479001600.f, Factorial.byTailRecursionGeneric 12.f) + Assert.AreEqual(2432902008176640000L, Factorial.byTailRecursionGeneric 20L) + Assert.AreEqual(2432902008176640000UL, Factorial.byTailRecursionGeneric 20UL) + Assert.AreEqual(2432902008176640000., Factorial.byTailRecursionGeneric 20.) + Assert.AreEqual(10888869450418352160768000000M, Factorial.byTailRecursionGeneric 27M) + + Assert.AreEqual( + 30414093201713378043612608166064768844377641568960512000000000000I, + Factorial.byTailRecursionGeneric 50I + ) From 8229192ac723f232411e41d78b372cc508417165 Mon Sep 17 00:00:00 2001 From: i1e0 <96235137+i1e0@users.noreply.github.com> Date: Thu, 6 Jan 2022 00:09:10 +0900 Subject: [PATCH 5/8] Rename and improve complexity of isPerfect --- Algorithms.Tests/Math/PerfectNumbersTests.fs | 10 +++++----- Algorithms/Math/PerfectNumbers.fs | 13 +++++++++++++ Algorithms/Math/Perfect_Numbers.fs | 13 ------------- 3 files changed, 18 insertions(+), 18 deletions(-) create mode 100644 Algorithms/Math/PerfectNumbers.fs delete mode 100644 Algorithms/Math/Perfect_Numbers.fs diff --git a/Algorithms.Tests/Math/PerfectNumbersTests.fs b/Algorithms.Tests/Math/PerfectNumbersTests.fs index df3a07b..46dc516 100644 --- a/Algorithms.Tests/Math/PerfectNumbersTests.fs +++ b/Algorithms.Tests/Math/PerfectNumbersTests.fs @@ -4,8 +4,8 @@ open Microsoft.VisualStudio.TestTools.UnitTesting open Algorithms.Math [] -type PerfectNumbersTests () = - +type PerfectNumbersTests() = + [] [] [] @@ -22,6 +22,6 @@ type PerfectNumbersTests () = [] [] [] - member this.IsPerfect (n: int, expected: bool) = - let actual = Perfect_Numbers.IsPerfect n - Assert.AreEqual(expected, actual) \ No newline at end of file + member this.Test(n: int, expected: bool) = + let actual = PerfectNumbers.isPerfect n + Assert.AreEqual(expected, actual) diff --git a/Algorithms/Math/PerfectNumbers.fs b/Algorithms/Math/PerfectNumbers.fs new file mode 100644 index 0000000..459fc60 --- /dev/null +++ b/Algorithms/Math/PerfectNumbers.fs @@ -0,0 +1,13 @@ +namespace Algorithms.Math + +module PerfectNumbers = + /// Check if a number is perfect. Time complexity: O(√n) + let isPerfect n = + match n with + | n when n <= 0 -> false + | n -> + { 1 .. n - 1 } + |> Seq.takeWhile (fun i -> i * i <= n) + |> Seq.filter ((%) n >> (=) 0) + |> Seq.fold (fun acc i -> acc + i + n / i) 0 + |> (=) (2 * n) diff --git a/Algorithms/Math/Perfect_Numbers.fs b/Algorithms/Math/Perfect_Numbers.fs deleted file mode 100644 index 27f2230..0000000 --- a/Algorithms/Math/Perfect_Numbers.fs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Algorithms.Math - -module Perfect_Numbers = - let IsPerfect (number: int) = - match number with - | number when number <= 0 -> false - | number -> - let total = - seq { 1 .. number - 1 } - |> Seq.filter (fun n -> number % n = 0) - |> Seq.sum - - total = number From 4c1329a48ebfab3fc2d8ad68f29ab31ace4c6245 Mon Sep 17 00:00:00 2001 From: i1e0 <96235137+i1e0@users.noreply.github.com> Date: Thu, 6 Jan 2022 00:18:31 +0900 Subject: [PATCH 6/8] update Power.fs and its tests --- Algorithms.Tests/Math/PowerTests.fs | 55 ++++++++++++++++++++++++++--- Algorithms/Math/Power.fs | 19 ++++++++-- 2 files changed, 67 insertions(+), 7 deletions(-) diff --git a/Algorithms.Tests/Math/PowerTests.fs b/Algorithms.Tests/Math/PowerTests.fs index c583641..2d049cc 100644 --- a/Algorithms.Tests/Math/PowerTests.fs +++ b/Algorithms.Tests/Math/PowerTests.fs @@ -4,9 +4,10 @@ open Microsoft.VisualStudio.TestTools.UnitTesting open Algorithms.Math [] -type PowerTests () = - +type PowerTests() = + [] + [] [] [] [] @@ -17,6 +18,50 @@ type PowerTests () = [] [] [] - member this.PowerOf (num: int, pow: int, expected: int) = - let actual = Power.Pow num pow - Assert.AreEqual(expected, actual) \ No newline at end of file + member this.FoldFunction_Valid(num: int, pow: int, expected: int) = + let actual = Power.byFoldFunction num pow + Assert.AreEqual(expected, actual) + + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + member this.ByRecursion_Valid(num: int, pow: int, expected: int) = + let actual = Power.byRecursion num pow + Assert.AreEqual(expected, actual) + + [] + [] + [] + member this.ByRecursion_Invalid(num: int, pow: int) = + let action = + new System.Action(fun () -> Power.byRecursion num pow |> ignore) + + Assert.ThrowsException(action) + |> ignore diff --git a/Algorithms/Math/Power.fs b/Algorithms/Math/Power.fs index 895826b..253a28f 100644 --- a/Algorithms/Math/Power.fs +++ b/Algorithms/Math/Power.fs @@ -1,5 +1,20 @@ namespace Algorithms.Math module Power = - let Pow x powerOf = - [1..powerOf] |> Seq.fold (fun acc _ -> acc * x) 1 \ No newline at end of file + /// Calculates x^n. Time complexity: O(√n). + let byFoldFunction x n = + { 1 .. n } |> Seq.fold (fun acc _ -> acc * x) 1 + + /// Calculates x^n. x and n can be negative. + /// Time complexity O(n). + let rec byRecursion x n = + match x, sign n with + | 0, -1 -> + System.DivideByZeroException "Attempted to divide by zero." + |> raise + | -1, _ -> if n % 2 = 0 then 1 else -1 + | 1, _ -> 1 + | _, 0 -> 1 + | 0, _ -> 0 + | _, -1 -> 0 + | _, _ -> x * byRecursion x (n - 1) From 0eafd474be2e87407be8a6a8c32ed1015341d075 Mon Sep 17 00:00:00 2001 From: i1e0 <96235137+i1e0@users.noreply.github.com> Date: Thu, 6 Jan 2022 00:23:38 +0900 Subject: [PATCH 7/8] Add Prime and its tests --- Algorithms.Tests/Math/PrimeTests.fs | 22 ++++++++++++++++++++++ Algorithms/Math/Prime.fs | 20 ++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 Algorithms.Tests/Math/PrimeTests.fs create mode 100644 Algorithms/Math/Prime.fs diff --git a/Algorithms.Tests/Math/PrimeTests.fs b/Algorithms.Tests/Math/PrimeTests.fs new file mode 100644 index 0000000..4abb0fe --- /dev/null +++ b/Algorithms.Tests/Math/PrimeTests.fs @@ -0,0 +1,22 @@ +namespace Algorithms.Tests.Math + +open Microsoft.VisualStudio.TestTools.UnitTesting +open Algorithms.Math + +[] +type PrimeTests() = + + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + member this.IsPrime(input: int, expected: bool) = + let actual = Prime.isPrime input + Assert.AreEqual(expected, actual) diff --git a/Algorithms/Math/Prime.fs b/Algorithms/Math/Prime.fs new file mode 100644 index 0000000..38c65ab --- /dev/null +++ b/Algorithms/Math/Prime.fs @@ -0,0 +1,20 @@ +namespace Algorithms.Math + +module Prime = + /// Check if a number is prime. Time complexity: O(√n) + let isPrime n = + if n <= 1 then + false + elif n = 2 then + true + elif n % 2 = 0 then + false + else + seq { + let mutable i = 3 + + while i * i <= n do + yield i + i <- i + 2 + } + |> Seq.forall ((%) n >> (<>) 0) From 8cef8117b60f659b8764f6508c15ef76e3ce94e3 Mon Sep 17 00:00:00 2001 From: i1e0 <96235137+i1e0@users.noreply.github.com> Date: Thu, 6 Jan 2022 00:24:09 +0900 Subject: [PATCH 8/8] Add tests for math functions --- Algorithms.Tests/Math/AbsMaxTests.fs | 13 +++++++++++++ Algorithms.Tests/Math/AbsMinTests.fs | 13 +++++++++++++ Algorithms.Tests/Math/AbsTests.fs | 17 +++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 Algorithms.Tests/Math/AbsMaxTests.fs create mode 100644 Algorithms.Tests/Math/AbsMinTests.fs create mode 100644 Algorithms.Tests/Math/AbsTests.fs diff --git a/Algorithms.Tests/Math/AbsMaxTests.fs b/Algorithms.Tests/Math/AbsMaxTests.fs new file mode 100644 index 0000000..5fd9ec1 --- /dev/null +++ b/Algorithms.Tests/Math/AbsMaxTests.fs @@ -0,0 +1,13 @@ +namespace Algorithms.Tests.Math + +open Microsoft.VisualStudio.TestTools.UnitTesting +open Algorithms.Math + +[] +type AbsMaxTests() = + + [] + member this.Test() = + Assert.AreEqual(-3, AbsMax.absMax [ -1; 1; 2; -2; -3; 3 ]) + Assert.AreEqual(3, AbsMax.absMax [ 1; -1; 2; -2; 3; -3 ]) + Assert.AreEqual(-1, AbsMax.absMax [ 0; -1; 0 ]) diff --git a/Algorithms.Tests/Math/AbsMinTests.fs b/Algorithms.Tests/Math/AbsMinTests.fs new file mode 100644 index 0000000..e39b215 --- /dev/null +++ b/Algorithms.Tests/Math/AbsMinTests.fs @@ -0,0 +1,13 @@ +namespace Algorithms.Tests.Math + +open Microsoft.VisualStudio.TestTools.UnitTesting +open Algorithms.Math + +[] +type AbsMinTests() = + + [] + member this.Test() = + Assert.AreEqual(-1, AbsMin.absMin [ -1; 1; 2; -2; -3; 3 ]) + Assert.AreEqual(1, AbsMin.absMin [ 1; -1; 2; -2; 3; -3 ]) + Assert.AreEqual(0, AbsMin.absMin [ 0; -1; 0 ]) diff --git a/Algorithms.Tests/Math/AbsTests.fs b/Algorithms.Tests/Math/AbsTests.fs new file mode 100644 index 0000000..9dfec5b --- /dev/null +++ b/Algorithms.Tests/Math/AbsTests.fs @@ -0,0 +1,17 @@ +namespace Algorithms.Tests.Math + +open Microsoft.VisualStudio.TestTools.UnitTesting +open Algorithms.Math + +[] +type AbsTests() = + + [] + [] + [] + [] + [] + [] + member this.Test(input: int, expected: int) = + let actual = Abs.absVal input + Assert.AreEqual(expected, actual)