OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library dart.pkg.math; | 5 library dart.pkg.math; |
6 | 6 |
7 // Placeholder library, reserved for future extension. | 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 |