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

Side by Side Diff: runtime/lib/bigint.dart

Issue 1199513003: Implement gcd in sdk. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 6 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
« no previous file with comments | « no previous file | runtime/lib/integers.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 // Copyright 2009 The Go Authors. All rights reserved. 5 // Copyright 2009 The Go Authors. All rights reserved.
6 // Use of this source code is governed by a BSD-style 6 // Use of this source code is governed by a BSD-style
7 // license that can be found in the LICENSE file. 7 // license that can be found in the LICENSE file.
8 8
9 /* 9 /*
10 * Copyright (c) 2003-2005 Tom Wu 10 * Copyright (c) 2003-2005 Tom Wu
(...skipping 29 matching lines...) Expand all
40 40
41 // A big integer number is represented by a sign, an array of 32-bit unsigned 41 // A big integer number is represented by a sign, an array of 32-bit unsigned
42 // integers in little endian format, and a number of used digits in that array. 42 // integers in little endian format, and a number of used digits in that array.
43 // The code makes sure that an even number of digits is always accessible and 43 // The code makes sure that an even number of digits is always accessible and
44 // meaningful, so that pairs of digits can be processed as 64-bit unsigned 44 // meaningful, so that pairs of digits can be processed as 64-bit unsigned
45 // numbers on a 64-bit platform. This requires the initialization of a leading 45 // numbers on a 64-bit platform. This requires the initialization of a leading
46 // zero if the number of used digits is odd. 46 // zero if the number of used digits is odd.
47 class _Bigint extends _IntegerImplementation implements int { 47 class _Bigint extends _IntegerImplementation implements int {
48 // Bits per digit. 48 // Bits per digit.
49 static const int _DIGIT_BITS = 32; 49 static const int _DIGIT_BITS = 32;
50 static const int _LOG2_DIGIT_BITS = 5;
50 static const int _DIGIT_BASE = 1 << _DIGIT_BITS; 51 static const int _DIGIT_BASE = 1 << _DIGIT_BITS;
51 static const int _DIGIT_MASK = (1 << _DIGIT_BITS) - 1; 52 static const int _DIGIT_MASK = (1 << _DIGIT_BITS) - 1;
52 53
53 // Bits per half digit. 54 // Bits per half digit.
54 static const int _DIGIT2_BITS = _DIGIT_BITS >> 1; 55 static const int _DIGIT2_BITS = _DIGIT_BITS >> 1;
55 static const int _DIGIT2_MASK = (1 << _DIGIT2_BITS) - 1; 56 static const int _DIGIT2_MASK = (1 << _DIGIT2_BITS) - 1;
56 57
57 // Min and max of non bigint values. 58 // Min and max of non bigint values.
58 static const int _MIN_INT64 = (-1) << 63; 59 static const int _MIN_INT64 = (-1) << 63;
59 static const int _MAX_INT64 = 0x7fffffffffffffff; 60 static const int _MAX_INT64 = 0x7fffffffffffffff;
(...skipping 1471 matching lines...) Expand 10 before | Expand all | Expand 10 after
1531 if (--i < 0) { 1532 if (--i < 0) {
1532 i = _DIGIT_BITS - 1; 1533 i = _DIGIT_BITS - 1;
1533 --j; 1534 --j;
1534 } 1535 }
1535 } 1536 }
1536 } 1537 }
1537 assert(!is1); 1538 assert(!is1);
1538 return z._revert(r_digits, r_used)._toValidInt(); 1539 return z._revert(r_digits, r_used)._toValidInt();
1539 } 1540 }
1540 1541
1541 // Returns 1/this % m, with m > 0. 1542 // If inv is false, returns gcd(x, y).
1542 int modInverse(int m) { 1543 // If inv is true and gcd(x, y) = 1, returns d, so that c*x + d*y = 1.
1543 if (m is! int) throw new ArgumentError(m); 1544 // If inv is true and gcd(x, y) != 1, throws RangeError("Not coprime").
1544 if (m <= 0) throw new RangeError(m); 1545 static int _binaryGcd(_Bigint x, _Bigint y, bool inv) {
1545 if (m == 1) return 0; 1546 var x_digits = x._digits;
1546 m = m._toBigint(); 1547 var y_digits = y._digits;
1547 var t = this; 1548 var x_used = x._used;
1548 if (t._neg || (t._absCompare(m) >= 0)) { 1549 var y_used = y._used;
1549 t %= m; 1550 var m_used = x_used > y_used ? x_used : y_used;
1550 t = t._toBigint(); 1551 final m_len = m_used + (m_used & 1);
1552 x_digits = _cloneDigits(x_digits, 0, x_used, m_len);
1553 y_digits = _cloneDigits(y_digits, 0, y_used, m_len);
1554 int s = 0;
1555 if (inv) {
1556 if ((y_used == 1) && (y_digits[0] == 1)) return 1;
1557 if ((y_used == 0) || (y_digits[0].isEven && x_digits[0].isEven)) {
1558 throw new RangeError("Not coprime");
1559 }
1560 } else {
1561 if ((x_used == 0) || (y_used == 0)) throw new RangeError(0);
1562 if (((x_used == 1) && (x_digits[0] == 1)) ||
1563 ((y_used == 1) && (y_digits[0] == 1))) return 1;
1564 bool xy_cloned = false;
1565 while (x.isEven && y.isEven) {
1566 _rsh(x_digits, x_used, 1, x_digits);
1567 _rsh(y_digits, y_used, 1, y_digits);
1568 s++;
1569 }
1570 if (s >= _DIGIT_BITS) {
1571 var sd = s >> _LOG2_DIGIT_BITS;
1572 x_used -= sd;
1573 y_used -= sd;
1574 m_used -= sd;
1575 }
1576 if ((y_digits[0] & 1) == 1) {
1577 var t_digits = x_digits;
1578 var t_used = x_used;
1579 x_digits = y_digits;
1580 x_used = y_used;
1581 y_digits = t_digits;
1582 y_used = t_used;
1583 }
1551 } 1584 }
1552 final bool ac = m.isEven; 1585 var u_digits = _cloneDigits(x_digits, 0, x_used, m_len);
1553 final t_used = t._used; 1586 var v_digits = _cloneDigits(y_digits, 0, y_used, m_len);
1554 if ((t_used == 1) && (t._digits[0] == 1)) return 1; 1587 final bool ac = (x_digits[0] & 1) == 0;
1555 if ((t_used == 0) || (ac && t.isEven)) throw new RangeError("Not coprime");
1556 final m_digits = m._digits;
1557 final m_used = m._used;
1558 final tuv_len = m_used + (m_used & 1);
1559 final t_digits = _cloneDigits(t._digits, 0, t_used, tuv_len);
1560 var u_digits = _cloneDigits(m_digits, 0, m_used, tuv_len);
1561 var v_digits = _cloneDigits(t_digits, 0, t_used, tuv_len);
1562 1588
1563 // Variables a, b, c, and d require one more digit. 1589 // Variables a, b, c, and d require one more digit.
1564 final abcd_used = m_used + 1; 1590 final abcd_used = m_used + 1;
1565 final abcd_len = abcd_used + (abcd_used & 1) + 2; // +2 to satisfy _absAdd. 1591 final abcd_len = abcd_used + (abcd_used & 1) + 2; // +2 to satisfy _absAdd.
1566 var a_digits, b_digits, c_digits, d_digits; 1592 var a_digits, b_digits, c_digits, d_digits;
1567 bool a_neg, b_neg, c_neg, d_neg; 1593 bool a_neg, b_neg, c_neg, d_neg;
1568 if (ac) { 1594 if (ac) {
1569 a_digits = new Uint32List(abcd_len); 1595 a_digits = new Uint32List(abcd_len);
1570 a_neg = false; 1596 a_neg = false;
1571 a_digits[0] = 1; 1597 a_digits[0] = 1;
1572 c_digits = new Uint32List(abcd_len); 1598 c_digits = new Uint32List(abcd_len);
1573 c_neg = false; 1599 c_neg = false;
1574 } 1600 }
1575 b_digits = new Uint32List(abcd_len); 1601 b_digits = new Uint32List(abcd_len);
1576 b_neg = false; 1602 b_neg = false;
1577 d_digits = new Uint32List(abcd_len); 1603 d_digits = new Uint32List(abcd_len);
1578 d_neg = false; 1604 d_neg = false;
1579 d_digits[0] = 1; 1605 d_digits[0] = 1;
1580 1606
1581 while (true) { 1607 while (true) {
1582 while ((u_digits[0] & 1) == 0) { 1608 while ((u_digits[0] & 1) == 0) {
1583 _rsh(u_digits, m_used, 1, u_digits); 1609 _rsh(u_digits, m_used, 1, u_digits);
1584 if (ac) { 1610 if (ac) {
1585 if (((a_digits[0] & 1) == 1) || ((b_digits[0] & 1) == 1)) { 1611 if (((a_digits[0] & 1) == 1) || ((b_digits[0] & 1) == 1)) {
1586 if (a_neg) { 1612 if (a_neg) {
1587 if ((a_digits[m_used] != 0) || 1613 if ((a_digits[m_used] != 0) ||
1588 (_compareDigits(a_digits, m_used, t_digits, m_used)) > 0) { 1614 (_compareDigits(a_digits, m_used, y_digits, m_used)) > 0) {
1589 _absSub(a_digits, abcd_used, t_digits, m_used, a_digits); 1615 _absSub(a_digits, abcd_used, y_digits, m_used, a_digits);
1590 } else { 1616 } else {
1591 _absSub(t_digits, m_used, a_digits, m_used, a_digits); 1617 _absSub(y_digits, m_used, a_digits, m_used, a_digits);
1592 a_neg = false; 1618 a_neg = false;
1593 } 1619 }
1594 } else { 1620 } else {
1595 _absAdd(a_digits, abcd_used, t_digits, m_used, a_digits); 1621 _absAdd(a_digits, abcd_used, y_digits, m_used, a_digits);
1596 } 1622 }
1597 if (b_neg) { 1623 if (b_neg) {
1598 _absAdd(b_digits, abcd_used, m_digits, m_used, b_digits); 1624 _absAdd(b_digits, abcd_used, x_digits, m_used, b_digits);
1599 } else if ((b_digits[m_used] != 0) || 1625 } else if ((b_digits[m_used] != 0) ||
1600 (_compareDigits(b_digits, m_used, m_digits, m_used) > 0)) { 1626 (_compareDigits(b_digits, m_used, x_digits, m_used) > 0)) {
1601 _absSub(b_digits, abcd_used, m_digits, m_used, b_digits); 1627 _absSub(b_digits, abcd_used, x_digits, m_used, b_digits);
1602 } else { 1628 } else {
1603 _absSub(m_digits, m_used, b_digits, m_used, b_digits); 1629 _absSub(x_digits, m_used, b_digits, m_used, b_digits);
1604 b_neg = true; 1630 b_neg = true;
1605 } 1631 }
1606 } 1632 }
1607 _rsh(a_digits, abcd_used, 1, a_digits); 1633 _rsh(a_digits, abcd_used, 1, a_digits);
1608 } else if ((b_digits[0] & 1) == 1) { 1634 } else if ((b_digits[0] & 1) == 1) {
1609 if (b_neg) { 1635 if (b_neg) {
1610 _absAdd(b_digits, abcd_used, m_digits, m_used, b_digits); 1636 _absAdd(b_digits, abcd_used, x_digits, m_used, b_digits);
1611 } else if ((b_digits[m_used] != 0) || 1637 } else if ((b_digits[m_used] != 0) ||
1612 (_compareDigits(b_digits, m_used, m_digits, m_used) > 0)) { 1638 (_compareDigits(b_digits, m_used, x_digits, m_used) > 0)) {
1613 _absSub(b_digits, abcd_used, m_digits, m_used, b_digits); 1639 _absSub(b_digits, abcd_used, x_digits, m_used, b_digits);
1614 } else { 1640 } else {
1615 _absSub(m_digits, m_used, b_digits, m_used, b_digits); 1641 _absSub(x_digits, m_used, b_digits, m_used, b_digits);
1616 b_neg = true; 1642 b_neg = true;
1617 } 1643 }
1618 } 1644 }
1619 _rsh(b_digits, abcd_used, 1, b_digits); 1645 _rsh(b_digits, abcd_used, 1, b_digits);
1620 } 1646 }
1621 while ((v_digits[0] & 1) == 0) { 1647 while ((v_digits[0] & 1) == 0) {
1622 _rsh(v_digits, m_used, 1, v_digits); 1648 _rsh(v_digits, m_used, 1, v_digits);
1623 if (ac) { 1649 if (ac) {
1624 if (((c_digits[0] & 1) == 1) || ((d_digits[0] & 1) == 1)) { 1650 if (((c_digits[0] & 1) == 1) || ((d_digits[0] & 1) == 1)) {
1625 if (c_neg) { 1651 if (c_neg) {
1626 if ((c_digits[m_used] != 0) || 1652 if ((c_digits[m_used] != 0) ||
1627 (_compareDigits(c_digits, m_used, t_digits, m_used) > 0)) { 1653 (_compareDigits(c_digits, m_used, y_digits, m_used) > 0)) {
1628 _absSub(c_digits, abcd_used, t_digits, m_used, c_digits); 1654 _absSub(c_digits, abcd_used, y_digits, m_used, c_digits);
1629 } else { 1655 } else {
1630 _absSub(t_digits, m_used, c_digits, m_used, c_digits); 1656 _absSub(y_digits, m_used, c_digits, m_used, c_digits);
1631 c_neg = false; 1657 c_neg = false;
1632 } 1658 }
1633 } else { 1659 } else {
1634 _absAdd(c_digits, abcd_used, t_digits, m_used, c_digits); 1660 _absAdd(c_digits, abcd_used, y_digits, m_used, c_digits);
1635 } 1661 }
1636 if (d_neg) { 1662 if (d_neg) {
1637 _absAdd(d_digits, abcd_used, m_digits, m_used, d_digits); 1663 _absAdd(d_digits, abcd_used, x_digits, m_used, d_digits);
1638 } else if ((d_digits[m_used] != 0) || 1664 } else if ((d_digits[m_used] != 0) ||
1639 (_compareDigits(d_digits, m_used, m_digits, m_used) > 0)) { 1665 (_compareDigits(d_digits, m_used, x_digits, m_used) > 0)) {
1640 _absSub(d_digits, abcd_used, m_digits, m_used, d_digits); 1666 _absSub(d_digits, abcd_used, x_digits, m_used, d_digits);
1641 } else { 1667 } else {
1642 _absSub(m_digits, m_used, d_digits, m_used, d_digits); 1668 _absSub(x_digits, m_used, d_digits, m_used, d_digits);
1643 d_neg = true; 1669 d_neg = true;
1644 } 1670 }
1645 } 1671 }
1646 _rsh(c_digits, abcd_used, 1, c_digits); 1672 _rsh(c_digits, abcd_used, 1, c_digits);
1647 } else if ((d_digits[0] & 1) == 1) { 1673 } else if ((d_digits[0] & 1) == 1) {
1648 if (d_neg) { 1674 if (d_neg) {
1649 _absAdd(d_digits, abcd_used, m_digits, m_used, d_digits); 1675 _absAdd(d_digits, abcd_used, x_digits, m_used, d_digits);
1650 } else if ((d_digits[m_used] != 0) || 1676 } else if ((d_digits[m_used] != 0) ||
1651 (_compareDigits(d_digits, m_used, m_digits, m_used) > 0)) { 1677 (_compareDigits(d_digits, m_used, x_digits, m_used) > 0)) {
1652 _absSub(d_digits, abcd_used, m_digits, m_used, d_digits); 1678 _absSub(d_digits, abcd_used, x_digits, m_used, d_digits);
1653 } else { 1679 } else {
1654 _absSub(m_digits, m_used, d_digits, m_used, d_digits); 1680 _absSub(x_digits, m_used, d_digits, m_used, d_digits);
1655 d_neg = true; 1681 d_neg = true;
1656 } 1682 }
1657 } 1683 }
1658 _rsh(d_digits, abcd_used, 1, d_digits); 1684 _rsh(d_digits, abcd_used, 1, d_digits);
1659 } 1685 }
1660 if (_compareDigits(u_digits, m_used, v_digits, m_used) >= 0) { 1686 if (_compareDigits(u_digits, m_used, v_digits, m_used) >= 0) {
1661 _absSub(u_digits, m_used, v_digits, m_used, u_digits); 1687 _absSub(u_digits, m_used, v_digits, m_used, u_digits);
1662 if (ac) { 1688 if (ac) {
1663 if (a_neg == c_neg) { 1689 if (a_neg == c_neg) {
1664 var a_cmp_c = 1690 var a_cmp_c =
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
1712 } 1738 }
1713 } else { 1739 } else {
1714 _absAdd(d_digits, abcd_used, b_digits, abcd_used, d_digits); 1740 _absAdd(d_digits, abcd_used, b_digits, abcd_used, d_digits);
1715 } 1741 }
1716 } 1742 }
1717 // Exit loop if u == 0. 1743 // Exit loop if u == 0.
1718 var i = m_used; 1744 var i = m_used;
1719 while ((i > 0) && (u_digits[i - 1] == 0)) --i; 1745 while ((i > 0) && (u_digits[i - 1] == 0)) --i;
1720 if (i == 0) break; 1746 if (i == 0) break;
1721 } 1747 }
1748 if (!inv) {
1749 if (s > 0) {
1750 _lsh(v_digits, m_used, s, v_digits);
1751 }
1752 return new _Bigint(false, m_used, v_digits)._toValidInt();
1753 }
1722 // No inverse if v != 1. 1754 // No inverse if v != 1.
1723 var i = m_used - 1; 1755 var i = m_used - 1;
1724 while ((i > 0) && (v_digits[i] == 0)) --i; 1756 while ((i > 0) && (v_digits[i] == 0)) --i;
1725 if ((i != 0) || (v_digits[0] != 1)) throw new RangeError("Not coprime"); 1757 if ((i != 0) || (v_digits[0] != 1)) throw new RangeError("Not coprime");
1726 1758
1727 if (d_neg) { 1759 if (d_neg) {
1728 if ((d_digits[m_used] != 0) || 1760 if ((d_digits[m_used] != 0) ||
1729 (_compareDigits(d_digits, m_used, m_digits, m_used) > 0)) { 1761 (_compareDigits(d_digits, m_used, x_digits, m_used) > 0)) {
1730 _absSub(d_digits, abcd_used, m_digits, m_used, d_digits); 1762 _absSub(d_digits, abcd_used, x_digits, m_used, d_digits);
1731 if ((d_digits[m_used] != 0) || 1763 if ((d_digits[m_used] != 0) ||
1732 (_compareDigits(d_digits, m_used, m_digits, m_used) > 0)) { 1764 (_compareDigits(d_digits, m_used, x_digits, m_used) > 0)) {
1733 _absSub(d_digits, abcd_used, m_digits, m_used, d_digits); 1765 _absSub(d_digits, abcd_used, x_digits, m_used, d_digits);
1734 } else { 1766 } else {
1735 _absSub(m_digits, m_used, d_digits, m_used, d_digits); 1767 _absSub(x_digits, m_used, d_digits, m_used, d_digits);
1736 d_neg = false; 1768 d_neg = false;
1737 } 1769 }
1738 } else { 1770 } else {
1739 _absSub(m_digits, m_used, d_digits, m_used, d_digits); 1771 _absSub(x_digits, m_used, d_digits, m_used, d_digits);
1740 d_neg = false; 1772 d_neg = false;
1741 } 1773 }
1742 } else if ((d_digits[m_used] != 0) || 1774 } else if ((d_digits[m_used] != 0) ||
1743 (_compareDigits(d_digits, m_used, m_digits, m_used) > 0)) { 1775 (_compareDigits(d_digits, m_used, x_digits, m_used) > 0)) {
1744 _absSub(d_digits, abcd_used, m_digits, m_used, d_digits); 1776 _absSub(d_digits, abcd_used, x_digits, m_used, d_digits);
1745 if ((d_digits[m_used] != 0) || 1777 if ((d_digits[m_used] != 0) ||
1746 (_compareDigits(d_digits, m_used, m_digits, m_used) > 0)) { 1778 (_compareDigits(d_digits, m_used, x_digits, m_used) > 0)) {
1747 _absSub(d_digits, abcd_used, m_digits, m_used, d_digits); 1779 _absSub(d_digits, abcd_used, x_digits, m_used, d_digits);
1748 } 1780 }
1749 } 1781 }
1750 return new _Bigint(false, m_used, d_digits)._toValidInt(); 1782 return new _Bigint(false, m_used, d_digits)._toValidInt();
1751 } 1783 }
1784
1785 // Returns 1/this % m, with m > 0.
1786 int modInverse(int m) {
1787 if (m is! int) throw new ArgumentError(m);
1788 if (m <= 0) throw new RangeError(m);
1789 if (m == 1) return 0;
1790 m = m._toBigint();
1791 var t = this;
1792 if (t._neg || (t._absCompare(m) >= 0)) {
1793 t %= m;
1794 t = t._toBigint();
1795 }
1796 return _binaryGcd(m, t, true);
1797 }
1798
1799 // Returns gcd of abs(this) and abs(other), with this != 0 and other !=0.
1800 int gcd(int other) {
1801 if (other is! int) throw new ArgumentError(other);
1802 return _binaryGcd(this, other._toBigint(), false);
1803 }
1752 } 1804 }
1753 1805
1754 // Interface for modular reduction. 1806 // Interface for modular reduction.
1755 class _Reduction { 1807 class _Reduction {
1756 // Return the number of digits used by r_digits. 1808 // Return the number of digits used by r_digits.
1757 int _convert(_Bigint x, Uint32List r_digits); 1809 int _convert(_Bigint x, Uint32List r_digits);
1758 int _mul(Uint32List x_digits, int x_used, 1810 int _mul(Uint32List x_digits, int x_used,
1759 Uint32List y_digits, int y_used, Uint32List r_digits); 1811 Uint32List y_digits, int y_used, Uint32List r_digits);
1760 int _sqr(Uint32List x_digits, int x_used, Uint32List r_digits); 1812 int _sqr(Uint32List x_digits, int x_used, Uint32List r_digits);
1761 1813
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after
2018 2070
2019 int _mul(Uint32List x_digits, int x_used, 2071 int _mul(Uint32List x_digits, int x_used,
2020 Uint32List y_digits, int y_used, 2072 Uint32List y_digits, int y_used,
2021 Uint32List r_digits) { 2073 Uint32List r_digits) {
2022 var r_used = _Bigint._mulDigits(x_digits, x_used, 2074 var r_used = _Bigint._mulDigits(x_digits, x_used,
2023 y_digits, y_used, 2075 y_digits, y_used,
2024 r_digits); 2076 r_digits);
2025 return _reduce(r_digits, r_used); 2077 return _reduce(r_digits, r_used);
2026 } 2078 }
2027 } 2079 }
OLDNEW
« no previous file with comments | « no previous file | runtime/lib/integers.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698