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

Unified 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: Tweaks Created 6 years, 3 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | pkg/math/test/bigint_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/math/lib/math.dart
diff --git a/pkg/math/lib/math.dart b/pkg/math/lib/math.dart
index 9958bec52ba1800eb71959658cd887967d62e4f5..323bcf7b4d66da6bab47b94ed916e0269343adf1 100644
--- a/pkg/math/lib/math.dart
+++ b/pkg/math/lib/math.dart
@@ -4,4 +4,151 @@
library dart.pkg.math;
-// Placeholder library, reserved for future extension.
+/**
+ * Computes the greatest common divisor between [a] and [b].
+ *
+ * The result is always positive even if either `a` or `b` is negative.
+ */
+int gcd(int a, int b) {
+ if (a == null) throw new ArgumentError(a);
+ if (b == null) throw new ArgumentError(b);
+ a = a.abs();
+ b = b.abs();
+
+ // Iterative Binary GCD algorithm.
+ if (a == 0) return b;
+ if (b == 0) return a;
+ int powerOfTwo = 1;
+ while (((a | b) & 1) == 0) {
+ powerOfTwo *= 2;
+ a ~/= 2;
+ b ~/= 2;
+ }
+
+ while (a.isEven) a ~/= 2;
+
+ do {
+ while (b.isEven) b ~/= 2;
+ if (a > b) {
+ int temp = b;
+ b = a;
+ a = temp;
+ }
+ b -= a;
+ } while (b != 0);
+
+ return a * powerOfTwo;
+}
+
+/**
+ * Computes the greatest common divisor between [a] and [b], as well as [x] and
+ * [y] such that `ax+by == gcd(a,b)`.
+ *
+ * The return value is a List of three ints: the greatest common divisor, `x`,
+ * and `y`, in that order.
+ */
+List<int> gcdext(int a, int b) {
+ if (a == null) throw new ArgumentError(a);
+ if (b == null) throw new ArgumentError(b);
+
+ if (a < 0) {
+ List<int> result = gcdext(-a, b);
+ result[1] = -result[1];
+ return result;
+ }
+ if (b < 0) {
+ List<int> result = gcdext(a, -b);
+ result[2] = -result[2];
+ return result;
+ }
+
+ int r0 = a;
+ int r1 = b;
+ int x0, x1, y0, y1;
+ x0 = y1 = 1;
+ x1 = y0 = 0;
+
+ while (r1 != 0) {
+ int q = r0 ~/ r1;
+ int tmp = r0;
+ r0 = r1;
+ r1 = tmp - q*r1;
+
+ tmp = x0;
+ x0 = x1;
+ x1 = tmp - q*x1;
+
+ tmp = y0;
+ y0 = y1;
+ y1 = tmp - q*y1;
+ }
+
+ return new List<int>(3)
+ ..[0] = r0
+ ..[1] = x0
+ ..[2] = y0;
+}
+
+/**
+ * Computes the inverse of [a] modulo [m].
+ *
+ * Throws an [IntegerDivisionByZeroException] if `a` has no inverse modulo `m`:
+ *
+ * invert(4, 7); // 2
+ * invert(4, 10); // throws IntegerDivisionByZeroException
+ */
+int invert(int a, int m) {
+ List<int> results = gcdext(a, m);
+ int g = results[0];
+ int x = results[1];
+ if (g != 1) {
+ throw new IntegerDivisionByZeroException();
+ }
+ return x % m;
+}
+
+/**
+ * Computes the least common multiple between [a] and [b].
+ */
+int lcm(int a, int b) {
+ if (a == null) throw new ArgumentError(a);
+ if (b == null) throw new ArgumentError(b);
+ if (a == 0 && b == 0) return 0;
+
+ return a.abs() ~/ gcd(a, b) * b.abs();
+}
+
+/**
+ * Computes [base] raised to [exp] modulo [mod].
+ *
+ * The result is always positive, in keeping with the behavior of modulus
+ * operator (`%`).
+ *
+ * Throws an [IntegerDivisionByZeroException] if `exp` is negative and `base`
+ * has no inverse modulo `mod`.
+ */
+int powmod(int base, int exp, int mod) {
+ if (base == null) throw new ArgumentError(base);
+ if (exp == null) throw new ArgumentError(exp);
+ if (mod == null) throw new ArgumentError(mod);
+
+ // Right-to-left binary method of modular exponentiation.
+ if (exp < 0) {
+ base = invert(base, mod);
+ exp = -exp;
+ }
+ if (exp == 0) { return 1; }
+
+ int result = 1;
+ base = base % mod;
+ while (true) {
+ if (exp.isOdd) {
+ result = (result * base) % mod;
+ }
+ exp ~/= 2;
+ if (exp == 0) {
+ return result;
+ }
+ base = (base * base) % mod;
+ }
+}
« no previous file with comments | « no previous file | pkg/math/test/bigint_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698