Chromium Code Reviews| 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 is! int) throw new ArgumentError(a); | |
|
Lasse Reichstein Nielsen
2014/08/26 07:44:26
Reduce this to just
if (a == null) ...
the "int"
srawlins
2014/08/29 06:43:25
Done.
| |
| 14 if (b is! int) 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 int temp; | |
| 23 while (((a | b) & 1) == 0) { | |
| 24 powerOfTwo *= 2; | |
| 25 a ~/= 2; | |
| 26 b ~/= 2; | |
| 27 } | |
| 28 | |
| 29 while (a.isEven) a ~/= 2; | |
| 30 | |
| 31 do { | |
| 32 while (b.isEven) b ~/= 2; | |
| 33 if (a > b) { | |
| 34 temp = b; | |
|
Lasse Reichstein Nielsen
2014/08/26 07:44:26
declare temp here.
srawlins
2014/08/29 06:43:25
Done.
| |
| 35 b = a; | |
| 36 a = temp; | |
| 37 } | |
| 38 b -= a; | |
| 39 } while (b != 0); | |
| 40 | |
| 41 return a * powerOfTwo; | |
| 42 } | |
| 43 | |
| 44 /** | |
| 45 * Computes the greatest common divisor between [a] and [b], as well as [x] and | |
| 46 * [y] such that `ax+by == gcd(a,b)`. | |
| 47 * | |
| 48 * The return value is a List of three ints: the greatest common divisor, `x`, | |
| 49 * and `y`, in that order. | |
| 50 */ | |
| 51 List<int> gcdext(int a, int b) { | |
| 52 if (a is! int) throw new ArgumentError(a); | |
| 53 if (b is! int) throw new ArgumentError(b); | |
| 54 | |
| 55 if (a < 0) { | |
| 56 List<int> results = gcdext(-a, b); | |
|
Lasse Reichstein Nielsen
2014/08/26 07:44:26
result[1] = -result[1];
return result;
No need to
srawlins
2014/08/29 06:43:25
:P I should have caught that. Thanks.
| |
| 57 return [results[0], -results[1], results[2]]; | |
| 58 } | |
| 59 if (b < 0) { | |
| 60 List<int> results = gcdext(a, -b); | |
| 61 return [results[0], results[1], -results[2]]; | |
| 62 } | |
| 63 | |
| 64 int g, x, y; | |
|
Lasse Reichstein Nielsen
2014/08/26 07:44:26
None of g, x, y are used below?
srawlins
2014/08/29 06:43:25
Done.
| |
| 65 int r0 = a; | |
| 66 int r1 = b; | |
| 67 int x0, x1, y0, y1, q, tmp; | |
| 68 x0 = y1 = 1; | |
| 69 x1 = y0 = 0; | |
| 70 | |
| 71 while (r1 != 0) { | |
|
Lasse Reichstein Nielsen
2014/08/26 07:44:26
Declare q and tmp inside the while.
srawlins
2014/08/29 06:43:25
Done.
| |
| 72 q = r0 ~/ r1; | |
| 73 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 [r0, x0, y0]; | |
|
Lasse Reichstein Nielsen
2014/08/26 07:44:26
Maybe use:
new List<int>(3)..[0] = r0 ..[1] = x0
srawlins
2014/08/29 06:43:25
Done, but spread out onto multiple lines. Should I
Lasse Reichstein Nielsen
2014/08/29 07:14:42
Multiple lines are fine.
| |
| 87 } | |
| 88 | |
| 89 /** | |
| 90 * Computes the inverse of [a] modulo [m]. | |
| 91 * | |
| 92 * Throws an IntegerDivisionByZeroException if `a` has no inverse modulo `m`: | |
|
Lasse Reichstein Nielsen
2014/08/26 07:44:26
[IntegerDivisionByZeroException]
(use square brack
srawlins
2014/08/29 06:43:24
Done.
| |
| 93 * | |
| 94 * invert(4, 7); // 2 | |
| 95 * invert(4, 10); // throws IntegerDivisionByZeroException | |
| 96 */ | |
| 97 int invert(int a, int m) { | |
| 98 List<int> results = gcdext(a, m); | |
| 99 int g = results[0]; | |
| 100 int x = results[1]; | |
| 101 if (g != 1) { | |
| 102 throw new IntegerDivisionByZeroException(); | |
| 103 } | |
| 104 return x % m; | |
| 105 } | |
| 106 | |
| 107 /** | |
| 108 * Computes the least common multiple between [a] and [b]. | |
| 109 */ | |
| 110 int lcm(int a, int b) { | |
| 111 if (a is! int) throw new ArgumentError(a); | |
| 112 if (b is! int) throw new ArgumentError(b); | |
| 113 if (a == 0 && b == 0) return 0; | |
| 114 | |
| 115 return a.abs() ~/ gcd(a, b) * b.abs(); | |
|
Lasse Reichstein Nielsen
2014/08/26 07:44:26
Nice touch to avoid overflows :)
srawlins
2014/08/29 06:43:24
Acknowledged.
| |
| 116 } | |
| 117 | |
| 118 /** | |
| 119 * Computes [base] raised to [exp] modulo [mod]. | |
| 120 * | |
| 121 * The result has the same sign as `mod`. | |
| 122 * | |
| 123 * Throws an IntegerDivisionByZeroException if `exp` is negative and `base` has | |
|
Lasse Reichstein Nielsen
2014/08/26 07:44:26
[]-quote the exception type.
srawlins
2014/08/29 06:43:25
Done.
| |
| 124 * no inverse modulo `mod`. | |
| 125 */ | |
| 126 int powmod(int base, int exp, int mod) { | |
|
Lasse Reichstein Nielsen
2014/08/26 07:44:26
If this method is expected to be used often with a
srawlins
2014/08/29 06:43:25
I don't think that is a common use case. One of th
| |
| 127 if (base is! int) throw new ArgumentError(base); | |
| 128 if (exp is! int) throw new ArgumentError(exp); | |
| 129 if (mod is! int) throw new ArgumentError(mod); | |
| 130 | |
| 131 // Right-to-left binary method of modular exponentiation. | |
| 132 if (exp < 0) { | |
| 133 base = invert(base, mod); | |
| 134 exp = -exp; | |
| 135 } | |
| 136 int result = 1; | |
| 137 base = base % mod; | |
| 138 while (exp != 0) { | |
| 139 if (exp.isOdd) { | |
| 140 result = (result * base) % mod; | |
| 141 } | |
| 142 exp ~/= 2; | |
| 143 base = (base * base) % mod; | |
|
Lasse Reichstein Nielsen
2014/08/26 07:44:26
This is executed one time too many. That's probabl
srawlins
2014/08/29 06:43:25
Good call. I'd not noticed that before. What about
Lasse Reichstein Nielsen
2014/08/29 07:14:42
It does. And I'd speed-check it too - having the e
srawlins
2014/09/02 19:49:23
Good call, I think the short circuit here helped m
| |
| 144 } | |
| 145 return result; | |
| 146 } | |
| OLD | NEW |