Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(600)

Side by Side Diff: pkg/math/lib/math.dart

Issue 475463005: Implement math.gcd in dart. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Adding lcm, gcdext, invert, and expmod, with tests Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | pkg/math/test/bigint_test.dart » ('j') | pkg/math/test/bigint_test.dart » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 }
OLDNEW
« no previous file with comments | « no previous file | pkg/math/test/bigint_test.dart » ('j') | pkg/math/test/bigint_test.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698