github.com/zhiqiangxu/util@v0.0.0-20230112053021-0a7aee056cd5/math/divisor.go (about)

     1  package math
     2  
     3  import "math/big"
     4  
     5  func DivCount(n int) int {
     6  
     7  	if n <= 0 {
     8  		panic("invalid input")
     9  	}
    10  	if n == 1 {
    11  		return 1
    12  	}
    13  
    14  	// store numbers in range [2,n]
    15  	numbers := make([]bool, n-1)
    16  	for i := range numbers {
    17  		numbers[i] = true
    18  	}
    19  
    20  	// sieve method for prime calculation
    21  	for i, v := range numbers {
    22  		p := i + 2
    23  		if v {
    24  			for j := i + p; j <= n-2; j += p {
    25  				numbers[j] = false
    26  			}
    27  		}
    28  		// if n can factor, then there's at least one <= sqrt(n)
    29  		if p*p >= n {
    30  			break
    31  		}
    32  	}
    33  
    34  	// Traversing through all prime numbers
    35  	total := 1
    36  	for i, v := range numbers {
    37  		if v {
    38  			// calculate number of divisor
    39  			// with formula total div =
    40  			// (p1+1) * (p2+1) *.....* (pn+1)
    41  			// where n = (a1^p1)*(a2^p2)....
    42  			// *(an^pn) ai being prime divisor
    43  			// for n and pi are their respective
    44  			// power in factorization
    45  			count := 0
    46  			p := i + 2
    47  			for n%p == 0 {
    48  				n /= p
    49  				count++
    50  			}
    51  			if count > 0 {
    52  				total *= 1 + count
    53  			}
    54  		}
    55  	}
    56  
    57  	return total
    58  }
    59  
    60  // AbelGroups returns the # of abel groups of order n
    61  // it's based on the fundamental theory of algebra that
    62  // every finitely generated abel group is isomorphic to
    63  // direct sum of prime-power cyclic groups.
    64  func AbelGroups(n int) *big.Int {
    65  	if n <= 0 {
    66  		panic("invalid input")
    67  	}
    68  	if n == 1 {
    69  		return big.NewInt(1)
    70  	}
    71  
    72  	// store numbers in range [2,n]
    73  	numbers := make([]bool, n-1)
    74  	for i := range numbers {
    75  		numbers[i] = true
    76  	}
    77  
    78  	// sieve method for prime calculation
    79  	for i, v := range numbers {
    80  		p := i + 2
    81  		if v {
    82  			for j := i + p; j <= n-2; j += p {
    83  				numbers[j] = false
    84  			}
    85  		}
    86  		// if n can factor, then there's at least one <= sqrt(n)
    87  		if p*p >= n {
    88  			break
    89  		}
    90  	}
    91  
    92  	// Traversing through all prime numbers
    93  	total := big.NewInt(1)
    94  	for i, v := range numbers {
    95  		if v {
    96  			count := 0
    97  			p := i + 2
    98  			for n%p == 0 {
    99  				n /= p
   100  				count++
   101  			}
   102  			if count > 0 {
   103  				total.Mul(total, Partition(count))
   104  			}
   105  		}
   106  	}
   107  
   108  	return total
   109  }