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

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

Issue 1188843004: Implement modInverse for an even modulus. (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 1524 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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 }
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