diff --git a/README.md b/README.md index a608159..8b3a928 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,8 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 6. [`MeanUsingRightShift`](./math/binary/arithmeticmean.go#L17): MeanUsingRightShift This function finds arithmetic mean using right shift 7. [`ReverseBits`](./math/binary/reversebits.go#L14): ReverseBits This function initialized the result by 0 (all bits 0) and process the given number starting from its least significant bit. If the current bit is 1, set the corresponding most significant bit in the result and finally move on to the next bit in the input number. Repeat this till all its bits are processed. 8. [`SequenceGrayCode`](./math/binary/rbc.go#L11): SequenceGrayCode The function generates an "Gray code" sequence of length n -9. [`XorSearchMissingNumber`](./math/binary/xorsearch.go#L11): XorSearchMissingNumber This function finds a missing number in a sequence +9. [`Sqrt`](./math/binary/sqrt.go#L16): No description provided. +10. [`XorSearchMissingNumber`](./math/binary/xorsearch.go#L11): XorSearchMissingNumber This function finds a missing number in a sequence ---
@@ -544,8 +545,10 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ##### Functions: 1. [`Abs`](./math/abs.go#L11): Abs returns absolute value -2. [`IsPowOfTwoUseLog`](./math/checkisnumberpoweroftwo.go#L10): IsPowOfTwoUseLog This function checks if a number is a power of two using the logarithm. The limiting degree can be from 0 to 63. See alternatives in the binary package. -3. [`Phi`](./math/eulertotient.go#L5): Phi is the Euler totient function. This function computes the number of numbers less then n that are coprime with n. +2. [`FindKthMax`](./math/kthnumber.go#L11): FindKthMax returns the kth large element given an integer slice with nil `error` if found and returns -1 with `error` `search.ErrNotFound` if not found. NOTE: The `nums` slice gets mutated in the process. +3. [`FindKthMin`](./math/kthnumber.go#L19): FindKthMin returns kth small element given an integer slice with nil `error` if found and returns -1 with `error` `search.ErrNotFound` if not found. NOTE: The `nums` slice gets mutated in the process. +4. [`IsPowOfTwoUseLog`](./math/checkisnumberpoweroftwo.go#L10): IsPowOfTwoUseLog This function checks if a number is a power of two using the logarithm. The limiting degree can be from 0 to 63. See alternatives in the binary package. +5. [`Phi`](./math/eulertotient.go#L5): Phi is the Euler totient function. This function computes the number of numbers less then n that are coprime with n. ---
@@ -860,13 +863,14 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 6. [`InsertionSort`](./sort/insertionsort.go#L3): No description provided. 7. [`MergeIter`](./sort/mergesort.go#L51): No description provided. 8. [`Mergesort`](./sort/mergesort.go#L37): Mergesort Perform mergesort on a slice of ints -9. [`Pigeonhole`](./sort/pigeonholesort.go#L12): Pigeonhole sorts a slice using pigeonhole sorting algorithm. -10. [`QuickSort`](./sort/quicksort.go#L37): QuickSort Sorts the entire array -11. [`QuickSortRange`](./sort/quicksort.go#L24): QuickSortRange Sorts the specified range within the array -12. [`RadixSort`](./sort/radixsort.go#L35): No description provided. -13. [`SelectionSort`](./sort/selectionsort.go#L3): No description provided. -14. [`ShellSort`](./sort/shellsort.go#L3): No description provided. -15. [`SimpleSort`](./sort/simplesort.go#L11): No description provided. +9. [`Partition`](./sort/quicksort.go#L10): No description provided. +10. [`Pigeonhole`](./sort/pigeonholesort.go#L12): Pigeonhole sorts a slice using pigeonhole sorting algorithm. +11. [`QuickSort`](./sort/quicksort.go#L37): QuickSort Sorts the entire array +12. [`QuickSortRange`](./sort/quicksort.go#L24): QuickSortRange Sorts the specified range within the array +13. [`RadixSort`](./sort/radixsort.go#L35): No description provided. +14. [`SelectionSort`](./sort/selectionsort.go#L3): No description provided. +15. [`ShellSort`](./sort/shellsort.go#L3): No description provided. +16. [`SimpleSort`](./sort/simplesort.go#L11): No description provided. --- ##### Types diff --git a/math/binary/sqrt.go b/math/binary/sqrt.go new file mode 100644 index 0000000..4d352ed --- /dev/null +++ b/math/binary/sqrt.go @@ -0,0 +1,24 @@ +// sqrt.go +// description: Square root calculation +// details: +// Calculating the square root using binary operations and a magic number 0x5f3759df [See more](https://en.wikipedia.org/wiki/Fast_inverse_square_root) +// author(s) [red_byte](https://github.com/i-redbyte) +// see sqrt_test.go + +package binary + +import ( + "math" +) + +const threeHalves = 1.5 + +func Sqrt(number float32) float32 { + var halfHumber, y float32 + halfHumber = number * 0.5 + z := math.Float32bits(number) + z = 0x5f3759df - (z >> 1) // floating point bit level hacking + y = math.Float32frombits(z) + y = y * (threeHalves - (halfHumber * y * y)) // Newton's approximation + return 1 / y +} diff --git a/math/binary/sqrt_test.go b/math/binary/sqrt_test.go new file mode 100644 index 0000000..426794f --- /dev/null +++ b/math/binary/sqrt_test.go @@ -0,0 +1,50 @@ +// sqrt_test.go +// description: Test for square root calculation +// author(s) [red_byte](https://github.com/i-redbyte) +// see sqrt.go + +package binary + +import ( + "math" + "testing" +) + +const epsilon = 0.2 + +func TestSquareRootCalculation(t *testing.T) { + tests := []struct { + name string + number float32 + want float64 + }{ + {"sqrt(1)", 1, 1}, + {"sqrt(9)", 9, 3}, + {"sqrt(25)", 25, 5}, + {"sqrt(121)", 121, 11}, + {"sqrt(10000)", 10000, 100}, + {"sqrt(169)", 169, 13}, + {"sqrt(0)", 0, 0}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := Sqrt(test.number) + delta := math.Abs(test.want - float64(got)) + if delta > epsilon { + t.Errorf("Sqrt() = %v, want %v delta %v", got, test.want, delta) + } + }) + } +} + +func BenchmarkSquareRootCalculation(b *testing.B) { + for i := 0; i < b.N; i++ { + Sqrt(225) + } +} + +func BenchmarkMathSqrt(b *testing.B) { + for i := 0; i < b.N; i++ { + math.Sqrt(225) + } +} diff --git a/math/kthnumber.go b/math/kthnumber.go new file mode 100644 index 0000000..802e2cf --- /dev/null +++ b/math/kthnumber.go @@ -0,0 +1,43 @@ +package math + +import ( + "github.com/TheAlgorithms/Go/search" + "github.com/TheAlgorithms/Go/sort" +) + +// FindKthMax returns the kth large element given an integer slice +// with nil `error` if found and returns -1 with `error` `search.ErrNotFound` +// if not found. NOTE: The `nums` slice gets mutated in the process. +func FindKthMax(nums []int, k int) (int, error) { + index := len(nums) - k + return kthNumber(nums, index) +} + +// FindKthMin returns kth small element given an integer slice +// with nil `error` if found and returns -1 with `error` `search.ErrNotFound` +// if not found. NOTE: The `nums` slice gets mutated in the process. +func FindKthMin(nums []int, k int) (int, error) { + index := k - 1 + return kthNumber(nums, index) +} + +// kthNumber use the selection algorithm (based on the partition method - the same one as used in quicksort). +func kthNumber(nums []int, k int) (int, error) { + if k < 0 || k >= len(nums) { + return -1, search.ErrNotFound + } + start := 0 + end := len(nums) - 1 + for start <= end { + pivot := sort.Partition(nums, start, end) + if k == pivot { + return nums[pivot], nil + } + if k > pivot { + start = pivot + 1 + continue + } + end = pivot - 1 + } + return -1, search.ErrNotFound +} diff --git a/math/kthnumber_test.go b/math/kthnumber_test.go new file mode 100644 index 0000000..558cf22 --- /dev/null +++ b/math/kthnumber_test.go @@ -0,0 +1,104 @@ +package math + +import ( + "github.com/TheAlgorithms/Go/search" + "testing" +) + +func TestFindKthMax(t *testing.T) { + sortTests := []struct { + input []int + k int + expected int + err error + name string + }{ + { + input: []int{6, 7, 0, -1, 10, 70, 8, 22, 3, 9}, + k: 3, + expected: 10, + name: "3th largest number", + }, + { + input: []int{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + k: 3, + expected: -1, + name: "3th largest number", + }, + { + input: []int{-1, -1, -1, -1, -1, -1}, + k: 7, + expected: -1, + err: search.ErrNotFound, + name: "This should be an error", + }, + { + input: []int{}, + k: 1, + expected: -1, + err: search.ErrNotFound, + name: "This should be an error", + }, + } + for _, test := range sortTests { + t.Run(test.name, func(t *testing.T) { + actual, err := FindKthMax(test.input, test.k) + if err != test.err { + t.Errorf("name:%v FindKthMax() = %v, want err: %v", test.name, err, test.err) + } + if actual != test.expected { + t.Errorf("test %s failed", test.name) + t.Errorf("actual %v expected %v", actual, test.expected) + } + }) + } +} + +func TestFindKthMin(t *testing.T) { + sortTests := []struct { + input []int + k int + expected int + err error + name string + }{ + { + input: []int{6, 7, 0, -1, 10, 70, 8, 22, 3, 9}, + k: 3, + expected: 3, + name: "3th smallest number", + }, + { + input: []int{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + k: 3, + expected: -1, + name: "3th smallest number", + }, + { + input: []int{-1, -1, -1, -1, -1, -1}, + k: 7, + expected: -1, + err: search.ErrNotFound, + name: "This should be an error", + }, + { + input: []int{}, + k: 1, + expected: -1, + err: search.ErrNotFound, + name: "This should be an error", + }, + } + for _, test := range sortTests { + t.Run(test.name, func(t *testing.T) { + actual, err := FindKthMin(test.input, test.k) + if err != test.err { + t.Errorf("name:%v FindKthMin() = %v, want err: %v", test.name, err, test.err) + } + if actual != test.expected { + t.Errorf("test %s failed", test.name) + t.Errorf("actual %v expected %v", actual, test.expected) + } + }) + } +} diff --git a/sort/quicksort.go b/sort/quicksort.go index 6ecbac2..36319cb 100644 --- a/sort/quicksort.go +++ b/sort/quicksort.go @@ -7,7 +7,7 @@ package sort -func partition(arr []int, low, high int) int { +func Partition(arr []int, low, high int) int { index := low - 1 pivotElement := arr[high] for i := low; i < high; i++ { @@ -27,7 +27,7 @@ func QuickSortRange(arr []int, low, high int) { } if low < high { - pivot := partition(arr, low, high) + pivot := Partition(arr, low, high) QuickSortRange(arr, low, pivot-1) QuickSortRange(arr, pivot+1, high) }