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 1524 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1535 } | 1535 } |
1536 } | 1536 } |
1537 assert(!is1); | 1537 assert(!is1); |
1538 return z._revert(r_digits, r_used)._toValidInt(); | 1538 return z._revert(r_digits, r_used)._toValidInt(); |
1539 } | 1539 } |
1540 | 1540 |
1541 // Returns 1/this % m, with m > 0. | 1541 // Returns 1/this % m, with m > 0. |
1542 int modInverse(int m) { | 1542 int modInverse(int m) { |
1543 if (m is! int) throw new ArgumentError(m); | 1543 if (m is! int) throw new ArgumentError(m); |
1544 if (m <= 0) throw new RangeError(m); | 1544 if (m <= 0) throw new RangeError(m); |
1545 if (_used == 0) return 0; | 1545 if (m == 1) return 0; |
1546 m = m._toBigint(); | 1546 m = m._toBigint(); |
1547 // TODO(regis): Implement modInverse for an even modulus. | |
1548 if (m.isEven) throw new UnimplementedError(); | |
1549 var t = this; | 1547 var t = this; |
1550 if ((t._compare(m) >= 0) || t._neg) { | 1548 if (t._neg || (t._absCompare(m) >= 0)) { |
1551 t %= m; | 1549 t %= m; |
1552 t = t._toBigint(); | 1550 t = t._toBigint(); |
1553 } | 1551 } |
| 1552 final bool ac = m.isEven; |
1554 final t_used = t._used; | 1553 final t_used = t._used; |
1555 if (t_used == 0) { | 1554 if ((t_used == 1) && (t._digits[0] == 1)) return 1; |
1556 return 0; // No inverse. | 1555 if ((t_used == 0) || (ac && t.isEven)) throw new RangeError("Not coprime"); |
1557 } | |
1558 final m_digits = m._digits; | 1556 final m_digits = m._digits; |
1559 final m_used = m._used; | 1557 final m_used = m._used; |
1560 final uv_len = m_used + (m_used & 1); | 1558 final tuv_len = m_used + (m_used & 1); |
1561 var v_digits = _cloneDigits(t._digits, 0, t_used, uv_len); | 1559 final t_digits = _cloneDigits(t._digits, 0, t_used, tuv_len); |
1562 var u_digits = _cloneDigits(m_digits, 0, m_used, uv_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); |
1563 | 1562 |
1564 // Variables b and d require one more digit for carry. | 1563 // Variables a, b, c, and d require one more digit. |
1565 final bd_used = m_used + 1; | 1564 final abcd_used = m_used + 1; |
1566 final bd_len = bd_used + (bd_used & 1); | 1565 final abcd_len = abcd_used + (abcd_used & 1) + 2; // +2 to satisfy _absAdd. |
1567 var b_digits = new Uint32List(bd_len); | 1566 var a_digits, b_digits, c_digits, d_digits; |
1568 var d_digits = new Uint32List(bd_len); | 1567 bool a_neg, b_neg, c_neg, d_neg; |
1569 bool b_neg = false; | 1568 if (ac) { |
1570 bool d_neg = false; | 1569 a_digits = new Uint32List(abcd_len); |
1571 | 1570 a_neg = false; |
| 1571 a_digits[0] = 1; |
| 1572 c_digits = new Uint32List(abcd_len); |
| 1573 c_neg = false; |
| 1574 } |
| 1575 b_digits = new Uint32List(abcd_len); |
| 1576 b_neg = false; |
| 1577 d_digits = new Uint32List(abcd_len); |
| 1578 d_neg = false; |
1572 d_digits[0] = 1; | 1579 d_digits[0] = 1; |
1573 | 1580 |
1574 while (true) { | 1581 while (true) { |
1575 while ((u_digits[0] & 1) == 0) { | 1582 while ((u_digits[0] & 1) == 0) { |
1576 _rsh(u_digits, m_used, 1, u_digits); | 1583 _rsh(u_digits, m_used, 1, u_digits); |
1577 if ((b_digits[0] & 1) == 1) { | 1584 if (ac) { |
1578 _absSub(m_digits, m_used, b_digits, m_used, b_digits); | 1585 if (((a_digits[0] & 1) == 1) || ((b_digits[0] & 1) == 1)) { |
1579 b_neg = !b_neg; | 1586 if (a_neg) { |
1580 } | 1587 if ((a_digits[m_used] != 0) || |
1581 _rsh(b_digits, m_used, 1, b_digits); | 1588 (_compareDigits(a_digits, m_used, t_digits, m_used)) > 0) { |
| 1589 _absSub(a_digits, abcd_used, t_digits, m_used, a_digits); |
| 1590 } else { |
| 1591 _absSub(t_digits, m_used, a_digits, m_used, a_digits); |
| 1592 a_neg = false; |
| 1593 } |
| 1594 } else { |
| 1595 _absAdd(a_digits, abcd_used, t_digits, m_used, a_digits); |
| 1596 } |
| 1597 if (b_neg) { |
| 1598 _absAdd(b_digits, abcd_used, m_digits, m_used, b_digits); |
| 1599 } else if ((b_digits[m_used] != 0) || |
| 1600 (_compareDigits(b_digits, m_used, m_digits, m_used) > 0)) { |
| 1601 _absSub(b_digits, abcd_used, m_digits, m_used, b_digits); |
| 1602 } else { |
| 1603 _absSub(m_digits, m_used, b_digits, m_used, b_digits); |
| 1604 b_neg = true; |
| 1605 } |
| 1606 } |
| 1607 _rsh(a_digits, abcd_used, 1, a_digits); |
| 1608 } else if ((b_digits[0] & 1) == 1) { |
| 1609 if (b_neg) { |
| 1610 _absAdd(b_digits, abcd_used, m_digits, m_used, b_digits); |
| 1611 } else if ((b_digits[m_used] != 0) || |
| 1612 (_compareDigits(b_digits, m_used, m_digits, m_used) > 0)) { |
| 1613 _absSub(b_digits, abcd_used, m_digits, m_used, b_digits); |
| 1614 } else { |
| 1615 _absSub(m_digits, m_used, b_digits, m_used, b_digits); |
| 1616 b_neg = true; |
| 1617 } |
| 1618 } |
| 1619 _rsh(b_digits, abcd_used, 1, b_digits); |
1582 } | 1620 } |
1583 while ((v_digits[0] & 1) == 0) { | 1621 while ((v_digits[0] & 1) == 0) { |
1584 _rsh(v_digits, m_used, 1, v_digits); | 1622 _rsh(v_digits, m_used, 1, v_digits); |
1585 if ((d_digits[0] & 1) == 1) { | 1623 if (ac) { |
1586 _absSub(m_digits, m_used, d_digits, m_used, d_digits); | 1624 if (((c_digits[0] & 1) == 1) || ((d_digits[0] & 1) == 1)) { |
1587 d_neg = !d_neg; | 1625 if (c_neg) { |
1588 } | 1626 if ((c_digits[m_used] != 0) || |
1589 _rsh(d_digits, m_used, 1, d_digits); | 1627 (_compareDigits(c_digits, m_used, t_digits, m_used) > 0)) { |
| 1628 _absSub(c_digits, abcd_used, t_digits, m_used, c_digits); |
| 1629 } else { |
| 1630 _absSub(t_digits, m_used, c_digits, m_used, c_digits); |
| 1631 c_neg = false; |
| 1632 } |
| 1633 } else { |
| 1634 _absAdd(c_digits, abcd_used, t_digits, m_used, c_digits); |
| 1635 } |
| 1636 if (d_neg) { |
| 1637 _absAdd(d_digits, abcd_used, m_digits, m_used, d_digits); |
| 1638 } else if ((d_digits[m_used] != 0) || |
| 1639 (_compareDigits(d_digits, m_used, m_digits, m_used) > 0)) { |
| 1640 _absSub(d_digits, abcd_used, m_digits, m_used, d_digits); |
| 1641 } else { |
| 1642 _absSub(m_digits, m_used, d_digits, m_used, d_digits); |
| 1643 d_neg = true; |
| 1644 } |
| 1645 } |
| 1646 _rsh(c_digits, abcd_used, 1, c_digits); |
| 1647 } else if ((d_digits[0] & 1) == 1) { |
| 1648 if (d_neg) { |
| 1649 _absAdd(d_digits, abcd_used, m_digits, m_used, d_digits); |
| 1650 } else if ((d_digits[m_used] != 0) || |
| 1651 (_compareDigits(d_digits, m_used, m_digits, m_used) > 0)) { |
| 1652 _absSub(d_digits, abcd_used, m_digits, m_used, d_digits); |
| 1653 } else { |
| 1654 _absSub(m_digits, m_used, d_digits, m_used, d_digits); |
| 1655 d_neg = true; |
| 1656 } |
| 1657 } |
| 1658 _rsh(d_digits, abcd_used, 1, d_digits); |
1590 } | 1659 } |
1591 if (_compareDigits(u_digits, m_used, v_digits, m_used) >= 0) { | 1660 if (_compareDigits(u_digits, m_used, v_digits, m_used) >= 0) { |
1592 _absSub(u_digits, m_used, v_digits, m_used, u_digits); | 1661 _absSub(u_digits, m_used, v_digits, m_used, u_digits); |
| 1662 if (ac) { |
| 1663 if (a_neg == c_neg) { |
| 1664 var a_cmp_c = |
| 1665 _compareDigits(a_digits, abcd_used, c_digits, abcd_used); |
| 1666 if (a_cmp_c > 0) { |
| 1667 _absSub(a_digits, abcd_used, c_digits, abcd_used, a_digits); |
| 1668 } else { |
| 1669 _absSub(c_digits, abcd_used, a_digits, abcd_used, a_digits); |
| 1670 a_neg = !a_neg && (a_cmp_c != 0); |
| 1671 } |
| 1672 } else { |
| 1673 _absAdd(a_digits, abcd_used, c_digits, abcd_used, a_digits); |
| 1674 } |
| 1675 } |
1593 if (b_neg == d_neg) { | 1676 if (b_neg == d_neg) { |
1594 if (_compareDigits(b_digits, m_used, d_digits, m_used) >= 0) { | 1677 var b_cmp_d = |
1595 _absSub(b_digits, m_used, d_digits, m_used, b_digits); | 1678 _compareDigits(b_digits, abcd_used, d_digits, abcd_used); |
1596 } else { | 1679 if (b_cmp_d > 0) { |
1597 _absSub(d_digits, m_used, b_digits, m_used, b_digits); | 1680 _absSub(b_digits, abcd_used, d_digits, abcd_used, b_digits); |
1598 b_neg = !b_neg; | 1681 } else { |
| 1682 _absSub(d_digits, abcd_used, b_digits, abcd_used, b_digits); |
| 1683 b_neg = !b_neg && (b_cmp_d != 0); |
1599 } | 1684 } |
1600 } else { | 1685 } else { |
1601 _absAdd(b_digits, m_used, d_digits, m_used, b_digits); | 1686 _absAdd(b_digits, abcd_used, d_digits, abcd_used, b_digits); |
1602 if ((b_digits[m_used] > 0) || | |
1603 (_compareDigits(b_digits, m_used, m_digits, m_used) > 0)) { | |
1604 _absSub(b_digits, bd_used, m_digits, m_used, b_digits); | |
1605 } | |
1606 } | 1687 } |
1607 } else { | 1688 } else { |
1608 _absSub(v_digits, m_used, u_digits, m_used, v_digits); | 1689 _absSub(v_digits, m_used, u_digits, m_used, v_digits); |
1609 if (b_neg == d_neg) { | 1690 if (ac) { |
1610 if (_compareDigits(d_digits, m_used, b_digits, m_used) >= 0) { | 1691 if (c_neg == a_neg) { |
1611 _absSub(d_digits, m_used, b_digits, m_used, d_digits); | 1692 var c_cmp_a = |
1612 } else { | 1693 _compareDigits(c_digits, abcd_used, a_digits, abcd_used); |
1613 _absSub(b_digits, m_used, d_digits, m_used, d_digits); | 1694 if (c_cmp_a > 0) { |
1614 d_neg = !d_neg; | 1695 _absSub(c_digits, abcd_used, a_digits, abcd_used, c_digits); |
| 1696 } else { |
| 1697 _absSub(a_digits, abcd_used, c_digits, abcd_used, c_digits); |
| 1698 c_neg = !c_neg && (c_cmp_a != 0); |
| 1699 } |
| 1700 } else { |
| 1701 _absAdd(c_digits, abcd_used, a_digits, abcd_used, c_digits); |
| 1702 } |
| 1703 } |
| 1704 if (d_neg == b_neg) { |
| 1705 var d_cmp_b = |
| 1706 _compareDigits(d_digits, abcd_used, b_digits, abcd_used); |
| 1707 if (d_cmp_b > 0) { |
| 1708 _absSub(d_digits, abcd_used, b_digits, abcd_used, d_digits); |
| 1709 } else { |
| 1710 _absSub(b_digits, abcd_used, d_digits, abcd_used, d_digits); |
| 1711 d_neg = !d_neg && (d_cmp_ab != 0); |
1615 } | 1712 } |
1616 } else { | 1713 } else { |
1617 _absAdd(d_digits, m_used, b_digits, m_used, d_digits); | 1714 _absAdd(d_digits, abcd_used, b_digits, abcd_used, d_digits); |
1618 if ((d_digits[m_used] > 0) || | |
1619 (_compareDigits(d_digits, m_used, m_digits, m_used) > 0)) { | |
1620 _absSub(d_digits, bd_used, m_digits, m_used, d_digits); | |
1621 } | |
1622 } | 1715 } |
1623 } | 1716 } |
1624 // Exit loop if u == 0. | 1717 // Exit loop if u == 0. |
1625 var i = m_used; | 1718 var i = m_used; |
1626 while ((i > 0) && (u_digits[i - 1] == 0)) { | 1719 while ((i > 0) && (u_digits[i - 1] == 0)) --i; |
1627 --i; | |
1628 } | |
1629 if (i == 0) break; | 1720 if (i == 0) break; |
1630 } | 1721 } |
1631 // No inverse if v != 1. | 1722 // No inverse if v != 1. |
1632 for (var i = m_used - 1; i > 0; --i) { | 1723 var i = m_used - 1; |
1633 if (v_digits[i] != 0) return 0; // No inverse. | 1724 while ((i > 0) && (v_digits[i] == 0)) --i; |
1634 } | 1725 if ((i != 0) || (v_digits[0] != 1)) throw new RangeError("Not coprime"); |
1635 if (v_digits[0] != 1) return 0; // No inverse. | |
1636 | 1726 |
1637 if (d_neg) { | 1727 if (d_neg) { |
1638 _absSub(m_digits, m_used, d_digits, m_used, d_digits); | 1728 if ((d_digits[m_used] != 0) || |
| 1729 (_compareDigits(d_digits, m_used, m_digits, m_used) > 0)) { |
| 1730 _absSub(d_digits, abcd_used, m_digits, m_used, d_digits); |
| 1731 if ((d_digits[m_used] != 0) || |
| 1732 (_compareDigits(d_digits, m_used, m_digits, m_used) > 0)) { |
| 1733 _absSub(d_digits, abcd_used, m_digits, m_used, d_digits); |
| 1734 } else { |
| 1735 _absSub(m_digits, m_used, d_digits, m_used, d_digits); |
| 1736 d_neg = false; |
| 1737 } |
| 1738 } else { |
| 1739 _absSub(m_digits, m_used, d_digits, m_used, d_digits); |
| 1740 d_neg = false; |
| 1741 } |
| 1742 } else if ((d_digits[m_used] != 0) || |
| 1743 (_compareDigits(d_digits, m_used, m_digits, m_used) > 0)) { |
| 1744 _absSub(d_digits, abcd_used, m_digits, m_used, d_digits); |
| 1745 if ((d_digits[m_used] != 0) || |
| 1746 (_compareDigits(d_digits, m_used, m_digits, m_used) > 0)) { |
| 1747 _absSub(d_digits, abcd_used, m_digits, m_used, d_digits); |
| 1748 } |
1639 } | 1749 } |
1640 return new _Bigint(false, m_used, d_digits)._toValidInt(); | 1750 return new _Bigint(false, m_used, d_digits)._toValidInt(); |
1641 } | 1751 } |
1642 } | 1752 } |
1643 | 1753 |
1644 // Interface for modular reduction. | 1754 // Interface for modular reduction. |
1645 class _Reduction { | 1755 class _Reduction { |
1646 // Return the number of digits used by r_digits. | 1756 // Return the number of digits used by r_digits. |
1647 int _convert(_Bigint x, Uint32List r_digits); | 1757 int _convert(_Bigint x, Uint32List r_digits); |
1648 int _mul(Uint32List x_digits, int x_used, | 1758 int _mul(Uint32List x_digits, int x_used, |
(...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1908 | 2018 |
1909 int _mul(Uint32List x_digits, int x_used, | 2019 int _mul(Uint32List x_digits, int x_used, |
1910 Uint32List y_digits, int y_used, | 2020 Uint32List y_digits, int y_used, |
1911 Uint32List r_digits) { | 2021 Uint32List r_digits) { |
1912 var r_used = _Bigint._mulDigits(x_digits, x_used, | 2022 var r_used = _Bigint._mulDigits(x_digits, x_used, |
1913 y_digits, y_used, | 2023 y_digits, y_used, |
1914 r_digits); | 2024 r_digits); |
1915 return _reduce(r_digits, r_used); | 2025 return _reduce(r_digits, r_used); |
1916 } | 2026 } |
1917 } | 2027 } |
OLD | NEW |