OLD | NEW |
| (Empty) |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library dart.pkg.math; | |
6 | |
7 /** | |
8 * Computes the greatest common divisor between [a] and [b]. | |
9 * | |
10 * The result is always positive even if either `a` or `b` is negative. | |
11 */ | |
12 int gcd(int a, int b) { | |
13 if (a == null) throw new ArgumentError(a); | |
14 if (b == null) throw new ArgumentError(b); | |
15 a = a.abs(); | |
16 b = b.abs(); | |
17 | |
18 // Iterative Binary GCD algorithm. | |
19 if (a == 0) return b; | |
20 if (b == 0) return a; | |
21 int powerOfTwo = 1; | |
22 while (((a | b) & 1) == 0) { | |
23 powerOfTwo *= 2; | |
24 a ~/= 2; | |
25 b ~/= 2; | |
26 } | |
27 | |
28 while (a.isEven) a ~/= 2; | |
29 | |
30 do { | |
31 while (b.isEven) b ~/= 2; | |
32 if (a > b) { | |
33 int temp = b; | |
34 b = a; | |
35 a = temp; | |
36 } | |
37 b -= a; | |
38 } while (b != 0); | |
39 | |
40 return a * powerOfTwo; | |
41 } | |
42 | |
43 /** | |
44 * Computes the greatest common divisor between [a] and [b], as well as [x] and | |
45 * [y] such that `ax+by == gcd(a,b)`. | |
46 * | |
47 * The return value is a List of three ints: the greatest common divisor, `x`, | |
48 * and `y`, in that order. | |
49 */ | |
50 List<int> gcdext(int a, int b) { | |
51 if (a == null) throw new ArgumentError(a); | |
52 if (b == null) throw new ArgumentError(b); | |
53 | |
54 if (a < 0) { | |
55 List<int> result = gcdext(-a, b); | |
56 result[1] = -result[1]; | |
57 return result; | |
58 } | |
59 if (b < 0) { | |
60 List<int> result = gcdext(a, -b); | |
61 result[2] = -result[2]; | |
62 return result; | |
63 } | |
64 | |
65 int r0 = a; | |
66 int r1 = b; | |
67 int x0, x1, y0, y1; | |
68 x0 = y1 = 1; | |
69 x1 = y0 = 0; | |
70 | |
71 while (r1 != 0) { | |
72 int q = r0 ~/ r1; | |
73 int tmp = r0; | |
74 r0 = r1; | |
75 r1 = tmp - q*r1; | |
76 | |
77 tmp = x0; | |
78 x0 = x1; | |
79 x1 = tmp - q*x1; | |
80 | |
81 tmp = y0; | |
82 y0 = y1; | |
83 y1 = tmp - q*y1; | |
84 } | |
85 | |
86 return new List<int>(3) | |
87 ..[0] = r0 | |
88 ..[1] = x0 | |
89 ..[2] = y0; | |
90 } | |
91 | |
92 /** | |
93 * Computes the inverse of [a] modulo [m]. | |
94 * | |
95 * Throws an [IntegerDivisionByZeroException] if `a` has no inverse modulo `m`: | |
96 * | |
97 * invert(4, 7); // 2 | |
98 * invert(4, 10); // throws IntegerDivisionByZeroException | |
99 */ | |
100 int invert(int a, int m) { | |
101 List<int> results = gcdext(a, m); | |
102 int g = results[0]; | |
103 int x = results[1]; | |
104 if (g != 1) { | |
105 throw new IntegerDivisionByZeroException(); | |
106 } | |
107 return x % m; | |
108 } | |
109 | |
110 /** | |
111 * Computes the least common multiple between [a] and [b]. | |
112 */ | |
113 int lcm(int a, int b) { | |
114 if (a == null) throw new ArgumentError(a); | |
115 if (b == null) throw new ArgumentError(b); | |
116 if (a == 0 && b == 0) return 0; | |
117 | |
118 return a.abs() ~/ gcd(a, b) * b.abs(); | |
119 } | |
120 | |
121 /** | |
122 * Computes [base] raised to [exp] modulo [mod]. | |
123 * | |
124 * The result is always positive, in keeping with the behavior of modulus | |
125 * operator (`%`). | |
126 * | |
127 * Throws an [IntegerDivisionByZeroException] if `exp` is negative and `base` | |
128 * has no inverse modulo `mod`. | |
129 */ | |
130 int powmod(int base, int exp, int mod) { | |
131 if (base == null) throw new ArgumentError(base); | |
132 if (exp == null) throw new ArgumentError(exp); | |
133 if (mod == null) throw new ArgumentError(mod); | |
134 | |
135 // Right-to-left binary method of modular exponentiation. | |
136 if (exp < 0) { | |
137 base = invert(base, mod); | |
138 exp = -exp; | |
139 } | |
140 if (exp == 0) { return 1; } | |
141 | |
142 int result = 1; | |
143 base = base % mod; | |
144 while (true) { | |
145 if (exp.isOdd) { | |
146 result = (result * base) % mod; | |
147 } | |
148 exp ~/= 2; | |
149 if (exp == 0) { | |
150 return result; | |
151 } | |
152 base = (base * base) % mod; | |
153 } | |
154 } | |
OLD | NEW |