1 module dkh.numeric.primitive; 2 3 import std.traits, std.bigint; 4 5 /// lcm 6 T lcm(T)(in T a, in T b) { 7 import std.numeric : gcd; 8 return a / gcd(a,b) * b; 9 } 10 11 /// 12 unittest { 13 assert(lcm(2, 4) == 4); 14 assert(lcm(3, 5) == 15); 15 assert(lcm(1, 1) == 1); 16 assert(lcm(0, 100) == 0); 17 } 18 19 /// 高速累乗 20 Unqual!T pow(T, U)(T x, U n) 21 if (!isFloatingPoint!T && (isIntegral!U || is(U == BigInt))) { 22 return pow(x, n, T(1)); 23 } 24 25 /// ditto 26 Unqual!T pow(T, U, V)(T x, U n, V e) 27 if ((isIntegral!U || is(U == BigInt)) && is(Unqual!T == Unqual!V)) { 28 Unqual!T b = x, v = e; 29 Unqual!U m = n; 30 while (m) { 31 if (m & 1) v *= b; 32 b *= b; 33 m /= 2; 34 } 35 return v; 36 } 37 38 unittest { 39 assert(pow(3, 5) == 243); 40 assert(pow(3, 5, 2) == 486); 41 } 42 43 /// 44 T powMod(T, U, V)(T x, U n, V md) 45 if (isIntegral!U || is(U == BigInt)) { 46 T r = T(1); 47 Unqual!U m = n; 48 while (m) { 49 if (m & 1) r = (r*x)%md; 50 x = (x*x)%md; 51 m >>= 1; 52 } 53 return r % md; 54 } 55 56 unittest { 57 immutable int B = 3; 58 assert(powMod(5, B, 100) == 25); //125 % 100 59 } 60 61 //todo: consider binary extgcd 62 /// a*T[0]+b*T[1]=T[2], T[2]=gcd 63 T[3] extGcd(T)(in T a, in T b) 64 if (!isIntegral!T || isSigned!T) //unsignedはNG 65 { 66 if (b==0) { 67 return [T(1), T(0), a]; 68 } else { 69 auto e = extGcd(b, a%b); 70 return [e[1], e[0]-a/b*e[1], e[2]]; 71 } 72 } 73 74 /// 75 unittest { 76 import std.numeric : gcd; 77 foreach (i; 0..100) { 78 foreach (j; 0..100) { 79 auto e = extGcd(i, j); 80 assert(e[2] == gcd(i, j)); 81 assert(e[0] * i + e[1] * j == e[2]); 82 } 83 } 84 } 85 86 /// calc inverse, (x * invMod(x)) % md == 1 87 T invMod(T)(T x, T md) { 88 auto r = extGcd!T(x, md); 89 assert(r[2] == 1); 90 auto z = r[0]; 91 return (z % md + md) % md; 92 } 93 94 unittest { 95 import std.numeric : gcd; 96 foreach (i; 1..100) { 97 foreach (j; 1..i) { 98 if (gcd(i, j) != 1) continue; 99 auto k = invMod(j, i); 100 assert(j * k % i == 1); 101 } 102 } 103 }