github.com/zhiqiangxu/util@v0.0.0-20230112053021-0a7aee056cd5/math/lambda.go (about) 1 package math 2 3 // FYI : https://www.math.sinica.edu.tw/www/file_upload/summer/crypt2017/data/2015/[20150707][carmichael].pdf 4 5 func Lambda(n int) int { 6 if n == 0 { 7 panic("invalid input") 8 } 9 if n == 1 { 10 return 1 11 } 12 13 factors := PrimeFactors(n) 14 15 var parts []int 16 for prime, power := range factors { 17 switch { 18 case prime == 2: 19 if power == 1 || power == 2 { 20 parts = append(parts, PowInts(2, power-1)) 21 } else { 22 parts = append(parts, PowInts(2, power-2)) 23 } 24 default: 25 parts = append(parts, PowInts(prime, power)-PowInts(prime, power-1)) 26 } 27 } 28 29 switch { 30 case len(parts) == 1: 31 return parts[0] 32 case len(parts) == 2: 33 return LCM(parts[0], parts[1]) 34 default: 35 return LCM(parts[0], parts[1], parts[2:]...) 36 } 37 } 38 39 // greatest common divisor (GCD) via Euclidean algorithm 40 func GCD(a, b int) int { 41 for b != 0 { 42 t := b 43 b = a % b 44 a = t 45 } 46 return a 47 } 48 49 // find Least Common Multiple (LCM) via GCD 50 func LCM(a, b int, integers ...int) int { 51 result := a * b / GCD(a, b) 52 53 for i := 0; i < len(integers); i++ { 54 result = LCM(result, integers[i]) 55 } 56 57 return result 58 } 59 60 // Assumption: n >= 0 61 func PowInts(x, n int) int { 62 if n == 0 { 63 return 1 64 } 65 66 v := 1 67 for n != 0 { 68 if n&1 == 1 { 69 v *= x 70 } 71 x *= x 72 n /= 2 73 } 74 75 return v 76 } 77 78 // Get all prime factors of a given number n 79 func PrimeFactors(n int) (pfs map[int]int) { 80 // Get the number of 2s that divide n 81 82 pfs = make(map[int]int) 83 for n%2 == 0 { 84 pfs[2] += 1 85 n = n / 2 86 } 87 88 // n must be odd at this point. so we can skip one element 89 // (note i = i + 2) 90 for i := 3; i*i <= n; i = i + 2 { 91 // while i divides n, append i and divide n 92 for n%i == 0 { 93 pfs[i] += 1 94 n = n / i 95 } 96 } 97 98 // This condition is to handle the case when n is a prime number 99 // greater than 2 100 if n > 2 { 101 pfs[n] += 1 102 } 103 104 return 105 }