Skip to content

Commit 54d2447

Browse files
math: Added PrimeList(n) and GetDivisors(n) (#193)
* Added new math functions: PrimeList, GetDivisors * coderabbitai suggetions, Fix some spelling mistakes and make the GetDivisors example more accurate --------- Co-authored-by: Kashif Khan <[email protected]>
1 parent 70c5e22 commit 54d2447

File tree

4 files changed

+246
-4
lines changed

4 files changed

+246
-4
lines changed

math/EXAMPLES.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,55 @@ func main() {
408408
```
409409
true
410410
false
411+
```
412+
---
413+
## `PrimeList`
414+
415+
### Get a list of prime numbers.
416+
417+
```go
418+
package main
419+
420+
import (
421+
"fmt"
422+
423+
utils "github.com/kashifkhan0771/utils/math"
424+
)
425+
426+
func main() {
427+
sl := utils.PrimeList(60)
428+
fmt.Println(sl)
429+
}
430+
```
431+
432+
#### Output:
411433

434+
```
435+
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59]
436+
```
437+
---
438+
## `GetDivisors`
439+
440+
### Get a list of divisors of a number.
441+
442+
```go
443+
package main
444+
445+
import (
446+
"fmt"
447+
448+
utils "github.com/kashifkhan0771/utils/math"
449+
)
450+
451+
func main() {
452+
sl := utils.GetDivisors(24)
453+
fmt.Println(sl)
454+
}
455+
```
456+
457+
#### Output:
458+
459+
```
460+
[1 24 2 12 3 8 4 6]
412461
```
413462
---

math/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@
2929

3030
- **IsPrime**: Checks if a number is prime or not. Only works for non-negative integers.
3131

32+
- **PrimeList**: Returns a slice of prime numbers up to n.
33+
34+
- **GetDivisors**: Returns the divisors of a positive integer as an unordered slice. Returns an empty slice for negative inputs.
35+
36+
37+
3238
## Examples:
3339

3440
For examples of each function, please checkout [EXAMPLES.md](/math/EXAMPLES.md)

math/math.go

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,14 +190,14 @@ func IsPrime(x int) bool {
190190
if x == 2 {
191191
return true
192192
}
193-
//no need to handle sqrt error since we elimnated negative numbers
193+
// No need to handle sqrt error since we elimnated negative numbers
194194
fsqrx, _ := Sqrt(x)
195195
sqrx := int(fsqrx)
196-
// if it's an even number that is not 2 then it's not a prime number
196+
// If it's an even number that is not 2 then it's not a prime number
197197
if x%2 == 0 {
198198
return false
199199
}
200-
//since we eliminated all even numbers we can just iterate over only odd numbers
200+
// Since we eliminated all even numbers we can just iterate over only odd numbers
201201
// I'm iterating up to sqrx+1 just to account for any rounding errors
202202
for i := 3; i <= sqrx+1; i += 2 {
203203
if x%i == 0 {
@@ -207,3 +207,51 @@ func IsPrime(x int) bool {
207207

208208
return true
209209
}
210+
211+
// Sieve of Eratosthenes algorithm Complexity = O(n log log n).
212+
func PrimeList(n int) []int {
213+
if n < 2 {
214+
return []int{}
215+
}
216+
list := []int{}
217+
// Slice of bool to flag each number, intially we assume every number is a prime number except 1 and 0
218+
isPrime := make([]bool, n+1)
219+
for i := 2; i <= n; i++ {
220+
isPrime[i] = true
221+
}
222+
// Basic implementation of Sieve
223+
for i := 2; i*i <= n; i++ {
224+
if isPrime[i] {
225+
for j := i + i; j <= n; j += i {
226+
isPrime[j] = false
227+
}
228+
}
229+
}
230+
for i := 2; i <= n; i++ {
231+
if isPrime[i] {
232+
list = append(list, i)
233+
}
234+
}
235+
236+
return list
237+
}
238+
239+
// Complexity = sqrt(n)
240+
func GetDivisors(n int) []int {
241+
if n <= 0 {
242+
return []int{}
243+
}
244+
// 2 is a good starting point for the slice capacity
245+
list := make([]int, 0, 2)
246+
for i := 1; i*i <= n; i++ {
247+
if n%i == 0 {
248+
list = append(list, i)
249+
// Check for perfect squares
250+
if i != n/i {
251+
list = append(list, n/i)
252+
}
253+
}
254+
}
255+
// The list is not sorted.
256+
return list
257+
}

math/math_test.go

Lines changed: 140 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package math
22

33
import (
44
"math"
5+
"slices"
56
"testing"
67
)
78

@@ -715,7 +716,7 @@ func TestIsPrime(t *testing.T) {
715716
}{
716717
{
717718
name: "success - negative 10",
718-
args: args{x: 10},
719+
args: args{x: -10},
719720
want: false,
720721
},
721722
{
@@ -763,6 +764,126 @@ func TestIsPrime(t *testing.T) {
763764
}
764765
}
765766

767+
func TestPrimeList(t *testing.T) {
768+
type args struct {
769+
x int
770+
}
771+
tests := []struct {
772+
name string
773+
args args
774+
want []int
775+
}{
776+
{
777+
name: "success - 2",
778+
args: args{x: 2},
779+
want: []int{2},
780+
},
781+
{
782+
name: "success - 0",
783+
args: args{x: 0},
784+
want: []int{},
785+
},
786+
{
787+
name: "success - 1",
788+
args: args{x: 1},
789+
want: []int{},
790+
},
791+
{
792+
name: "success - 3",
793+
args: args{x: 3},
794+
want: []int{2, 3},
795+
},
796+
{
797+
name: "success - 4",
798+
args: args{x: 4},
799+
want: []int{2, 3},
800+
},
801+
{
802+
name: "success - 10",
803+
args: args{x: 10},
804+
want: []int{2, 3, 5, 7},
805+
},
806+
{
807+
name: "success - 100 ",
808+
args: args{x: 100},
809+
want: []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97},
810+
},
811+
}
812+
for _, tt := range tests {
813+
t.Run(tt.name, func(t *testing.T) {
814+
if got := PrimeList(tt.args.x); !slices.Equal(got, tt.want) {
815+
t.Errorf("PrimeList() = %v, want %v", got, tt.want)
816+
}
817+
})
818+
}
819+
}
820+
func TestGetDivisors(t *testing.T) {
821+
type args struct {
822+
x int
823+
}
824+
tests := []struct {
825+
name string
826+
args args
827+
want []int
828+
}{
829+
{
830+
name: "success - 0",
831+
args: args{x: 0},
832+
want: []int{},
833+
},
834+
{
835+
name: "success - 1",
836+
args: args{x: 1},
837+
want: []int{1},
838+
},
839+
{
840+
name: "success - 2",
841+
args: args{x: 2},
842+
want: []int{1, 2},
843+
},
844+
{
845+
name: "success - 3",
846+
args: args{x: 3},
847+
want: []int{1, 3},
848+
},
849+
{
850+
name: "success - 4",
851+
args: args{x: 4},
852+
want: []int{1, 2, 4},
853+
},
854+
{
855+
name: "success - 10",
856+
args: args{x: 10},
857+
want: []int{1, 2, 5, 10},
858+
},
859+
{
860+
name: "success - 49",
861+
args: args{x: 49},
862+
want: []int{1, 7, 49},
863+
},
864+
{
865+
name: "success - 48",
866+
args: args{x: 48},
867+
want: []int{1, 2, 3, 4, 6, 8, 12, 16, 24, 48},
868+
},
869+
{
870+
name: "success - 100 ",
871+
args: args{x: 100},
872+
want: []int{1, 2, 4, 5, 10, 20, 25, 50, 100},
873+
},
874+
}
875+
for _, tt := range tests {
876+
t.Run(tt.name, func(t *testing.T) {
877+
got := GetDivisors(tt.args.x)
878+
// The slice need to be sorted in order to be compared
879+
slices.Sort(got)
880+
if !slices.Equal(got, tt.want) {
881+
t.Errorf("GetDivisors() = %v, want %v", got, tt.want)
882+
}
883+
})
884+
}
885+
}
886+
766887
// ================================================================================
767888
// ### BENCHMARKS
768889
// ================================================================================
@@ -819,3 +940,21 @@ func BenchmarkIsPrime(b *testing.B) {
819940
_ = IsPrime(prime)
820941
}
821942
}
943+
944+
func BenchmarkPrimeList(b *testing.B) {
945+
b.ReportAllocs()
946+
947+
const n = 1e8
948+
for b.Loop() {
949+
_ = PrimeList(n)
950+
}
951+
}
952+
953+
func BenchmarkGetDivisors(b *testing.B) {
954+
b.ReportAllocs()
955+
956+
const n = 2e9
957+
for b.Loop() {
958+
_ = GetDivisors(n)
959+
}
960+
}

0 commit comments

Comments
 (0)