OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |