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 |