Index: runtime/lib/bigint.dart |
diff --git a/runtime/lib/bigint.dart b/runtime/lib/bigint.dart |
index f4ff408348d367f93d1ddc4c9ad94aa1bfd87ab8..60b42454946acfb08790da4bd7c2fb8c23c8ee11 100644 |
--- a/runtime/lib/bigint.dart |
+++ b/runtime/lib/bigint.dart |
@@ -1265,15 +1265,9 @@ class _Bigint extends _IntegerImplementation implements int { |
return other._toBigintOrDouble()._mulFromInteger(this); |
} |
num operator ~/(num other) { |
- if ((other is int) && (other == 0)) { |
- throw const IntegerDivisionByZeroException(); |
- } |
return other._toBigintOrDouble()._truncDivFromInteger(this); |
} |
num operator %(num other) { |
- if ((other is int) && (other == 0)) { |
- throw const IntegerDivisionByZeroException(); |
- } |
return other._toBigintOrDouble()._moduloFromInteger(this); |
} |
int operator &(int other) { |
@@ -1368,9 +1362,15 @@ class _Bigint extends _IntegerImplementation implements int { |
return other._toBigint()._mul(this)._toValidInt(); |
} |
int _truncDivFromInteger(int other) { |
+ if (_used == 0) { |
+ throw const IntegerDivisionByZeroException(); |
+ } |
return other._toBigint()._div(this)._toValidInt(); |
} |
int _moduloFromInteger(int other) { |
+ if (_used == 0) { |
+ throw const IntegerDivisionByZeroException(); |
+ } |
_Bigint result = other._toBigint()._rem(this); |
if (result._neg) { |
if (_neg) { |
@@ -1382,6 +1382,9 @@ class _Bigint extends _IntegerImplementation implements int { |
return result._toValidInt(); |
} |
int _remainderFromInteger(int other) { |
+ if (_used == 0) { |
+ throw const IntegerDivisionByZeroException(); |
+ } |
return other._toBigint()._rem(this)._toValidInt(); |
} |
bool _greaterThanFromInteger(int other) { |
@@ -1534,6 +1537,107 @@ class _Bigint extends _IntegerImplementation implements int { |
assert(!is1); |
return z._revert(r_digits, r_used)._toValidInt(); |
} |
+ |
+ // Returns 1/this % m, with m > 0. |
+ int modInverse(int m) { |
+ if (m is! int) throw new ArgumentError(m); |
+ if (m <= 0) throw new RangeError(m); |
+ m = m._toBigint(); |
+ // TODO(regis): Implement modInverse for an even modulus. |
+ if (m.isEven) throw new UnimplementedError(); |
+ var t = this; |
+ if ((t._compare(m) >= 0) || t._neg) { |
+ t %= m; |
+ t = t._toBigint(); |
+ } |
+ final t_used = t._used; |
+ if (t_used == 0) { |
+ return 0; // No inverse. |
+ } |
+ final m_digits = m._digits; |
+ final m_used = m._used; |
+ final uv_len = m_used + (m_used & 1); |
+ var v_digits = _cloneDigits(t._digits, 0, t_used, uv_len); |
+ var u_digits = _cloneDigits(m_digits, 0, m_used, uv_len); |
+ |
+ // Variables b and d require one more digit for carry. |
+ final bd_used = m_used + 1; |
+ final bd_len = bd_used + (bd_used & 1); |
+ var b_digits = new Uint32List(bd_len); |
+ var d_digits = new Uint32List(bd_len); |
+ bool b_neg = false; |
+ bool d_neg = false; |
+ |
+ d_digits[0] = 1; |
+ |
+ while (true) { |
+ while ((u_digits[0] & 1) == 0) { |
+ _rsh(u_digits, m_used, 1, u_digits); |
+ if ((b_digits[0] & 1) == 1) { |
+ _absSub(m_digits, m_used, b_digits, m_used, b_digits); |
+ b_neg = !b_neg; |
+ } |
+ _rsh(b_digits, m_used, 1, b_digits); |
+ } |
+ while ((v_digits[0] & 1) == 0) { |
+ _rsh(v_digits, m_used, 1, v_digits); |
+ if ((d_digits[0] & 1) == 1) { |
+ _absSub(m_digits, m_used, d_digits, m_used, d_digits); |
+ d_neg = !d_neg; |
+ } |
+ _rsh(d_digits, m_used, 1, d_digits); |
+ } |
+ if (_compareDigits(u_digits, m_used, v_digits, m_used) >= 0) { |
+ _absSub(u_digits, m_used, v_digits, m_used, u_digits); |
+ if (b_neg == d_neg) { |
+ if (_compareDigits(b_digits, m_used, d_digits, m_used) >= 0) { |
+ _absSub(b_digits, m_used, d_digits, m_used, b_digits); |
+ } else { |
+ _absSub(d_digits, m_used, b_digits, m_used, b_digits); |
+ b_neg = !b_neg; |
+ } |
+ } else { |
+ _absAdd(b_digits, m_used, d_digits, m_used, b_digits); |
+ if ((b_digits[m_used] > 0) || |
+ (_compareDigits(b_digits, m_used, m_digits, m_used) > 0)) { |
+ _absSub(b_digits, bd_used, m_digits, m_used, b_digits); |
+ } |
+ } |
+ } else { |
+ _absSub(v_digits, m_used, u_digits, m_used, v_digits); |
+ if (b_neg == d_neg) { |
+ if (_compareDigits(d_digits, m_used, b_digits, m_used) >= 0) { |
+ _absSub(d_digits, m_used, b_digits, m_used, d_digits); |
+ } else { |
+ _absSub(b_digits, m_used, d_digits, m_used, d_digits); |
+ d_neg = !d_neg; |
+ } |
+ } else { |
+ _absAdd(d_digits, m_used, b_digits, m_used, d_digits); |
+ if ((d_digits[m_used] > 0) || |
+ (_compareDigits(d_digits, m_used, m_digits, m_used) > 0)) { |
+ _absSub(d_digits, bd_used, m_digits, m_used, d_digits); |
+ } |
+ } |
+ } |
+ // Exit loop if u == 0. |
+ var i = m_used; |
+ while ((i > 0) && (u_digits[i - 1] == 0)) { |
+ --i; |
+ } |
+ if (i == 0) break; |
+ } |
+ // No inverse if v != 1. |
+ for (var i = m_used - 1; i > 0; --i) { |
+ if (v_digits[i] != 0) return 0; // No inverse. |
+ } |
+ if (v_digits[0] != 1) return 0; // No inverse. |
+ |
+ if (d_neg) { |
+ _absSub(m_digits, m_used, d_digits, m_used, d_digits); |
+ } |
+ return new _Bigint(false, m_used, d_digits)._toValidInt(); |
+ } |
} |
// Interface for modular reduction. |