| ... | ... | @@ -15,6 +15,8 @@ const maxInt = std.math.maxInt; |
| 15 | 15 | const minInt = std.math.minInt; |
| 16 | 16 | const assert = std.debug.assert; |
| 17 | 17 | |
| 18 | const debug_safety = false; |
| 19 | |
| 18 | 20 | /// Returns the number of limbs needed to store `scalar`, which must be a |
| 19 | 21 | /// primitive integer value. |
| 20 | 22 | pub fn calcLimbLen(scalar: anytype) usize { |
| ... | ... | @@ -57,7 +59,7 @@ pub fn calcSetStringLimbCount(base: u8, string_len: usize) usize { |
| 57 | 59 | |
| 58 | 60 | /// a + b * c + *carry, sets carry to the overflow bits |
| 59 | 61 | pub fn addMulLimbWithCarry(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb { |
| 60 | | @setRuntimeSafety(false); |
| 62 | @setRuntimeSafety(debug_safety); |
| 61 | 63 | var r1: Limb = undefined; |
| 62 | 64 | |
| 63 | 65 | // r1 = a + *carry |
| ... | ... | @@ -1529,8 +1531,7 @@ pub const Managed = struct { |
| 1529 | 1531 | /// self's allocator is used for temporary storage to boost multiplication performance. |
| 1530 | 1532 | pub fn setString(self: *Managed, base: u8, value: []const u8) !void { |
| 1531 | 1533 | if (base < 2 or base > 16) return error.InvalidBase; |
| 1532 | | const den = (@sizeOf(Limb) * 8 / base); |
| 1533 | | try self.ensureCapacity((value.len + (den - 1)) / den); |
| 1534 | try self.ensureCapacity(calcSetStringLimbCount(base, value.len)); |
| 1534 | 1535 | const limbs_buffer = try self.allocator.alloc(Limb, calcSetStringLimbsBufferLen(base, value.len)); |
| 1535 | 1536 | defer self.allocator.free(limbs_buffer); |
| 1536 | 1537 | var m = self.toMutable(); |
| ... | ... | @@ -1646,17 +1647,19 @@ pub const Managed = struct { |
| 1646 | 1647 | /// rma = a * b |
| 1647 | 1648 | /// |
| 1648 | 1649 | /// rma, a and b may be aliases. However, it is more efficient if rma does not alias a or b. |
| 1650 | /// If rma aliases a or b, then caller must call `rma.ensureMulCapacity` prior to calling `mul`. |
| 1649 | 1651 | /// |
| 1650 | 1652 | /// Returns an error if memory could not be allocated. |
| 1651 | 1653 | /// |
| 1652 | 1654 | /// rma's allocator is used for temporary storage to speed up the multiplication. |
| 1653 | 1655 | pub fn mul(rma: *Managed, a: Const, b: Const) !void { |
| 1654 | | try rma.ensureCapacity(a.limbs.len + b.limbs.len + 1); |
| 1655 | 1656 | var alias_count: usize = 0; |
| 1656 | 1657 | if (rma.limbs.ptr == a.limbs.ptr) |
| 1657 | 1658 | alias_count += 1; |
| 1658 | 1659 | if (rma.limbs.ptr == b.limbs.ptr) |
| 1659 | 1660 | alias_count += 1; |
| 1661 | assert(alias_count == 0 or rma.limbs.len >= a.limbs.len + b.limbs.len + 1); |
| 1662 | try rma.ensureMulCapacity(a, b); |
| 1660 | 1663 | var m = rma.toMutable(); |
| 1661 | 1664 | if (alias_count == 0) { |
| 1662 | 1665 | m.mulNoAlias(a, b, rma.allocator); |
| ... | ... | @@ -1669,6 +1672,10 @@ pub const Managed = struct { |
| 1669 | 1672 | rma.setMetadata(m.positive, m.len); |
| 1670 | 1673 | } |
| 1671 | 1674 | |
| 1675 | pub fn ensureMulCapacity(rma: *Managed, a: Const, b: Const) !void { |
| 1676 | try rma.ensureCapacity(a.limbs.len + b.limbs.len + 1); |
| 1677 | } |
| 1678 | |
| 1672 | 1679 | /// q = a / b (rem r) |
| 1673 | 1680 | /// |
| 1674 | 1681 | /// a / b are floored (rounded towards 0). |
| ... | ... | @@ -1773,7 +1780,7 @@ pub const Managed = struct { |
| 1773 | 1780 | /// |
| 1774 | 1781 | /// r MUST NOT alias any of a or b. |
| 1775 | 1782 | fn llmulacc(opt_allocator: ?*Allocator, r: []Limb, a: []const Limb, b: []const Limb) void { |
| 1776 | | @setRuntimeSafety(false); |
| 1783 | @setRuntimeSafety(debug_safety); |
| 1777 | 1784 | |
| 1778 | 1785 | const a_norm = a[0..llnormalize(a)]; |
| 1779 | 1786 | const b_norm = b[0..llnormalize(b)]; |
| ... | ... | @@ -1806,7 +1813,7 @@ fn llmulacc(opt_allocator: ?*Allocator, r: []Limb, a: []const Limb, b: []const L |
| 1806 | 1813 | /// |
| 1807 | 1814 | /// r MUST NOT alias any of a or b. |
| 1808 | 1815 | fn llmulacc_karatsuba(allocator: *Allocator, r: []Limb, x: []const Limb, y: []const Limb) error{OutOfMemory}!void { |
| 1809 | | @setRuntimeSafety(false); |
| 1816 | @setRuntimeSafety(debug_safety); |
| 1810 | 1817 | |
| 1811 | 1818 | assert(r.len >= x.len + y.len + 1); |
| 1812 | 1819 | |
| ... | ... | @@ -1873,7 +1880,7 @@ fn llmulacc_karatsuba(allocator: *Allocator, r: []Limb, x: []const Limb, y: []co |
| 1873 | 1880 | |
| 1874 | 1881 | // r = r + a |
| 1875 | 1882 | fn llaccum(r: []Limb, a: []const Limb) Limb { |
| 1876 | | @setRuntimeSafety(false); |
| 1883 | @setRuntimeSafety(debug_safety); |
| 1877 | 1884 | assert(r.len != 0 and a.len != 0); |
| 1878 | 1885 | assert(r.len >= a.len); |
| 1879 | 1886 | |
| ... | ... | @@ -1896,7 +1903,7 @@ fn llaccum(r: []Limb, a: []const Limb) Limb { |
| 1896 | 1903 | |
| 1897 | 1904 | /// Returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively for limbs. |
| 1898 | 1905 | pub fn llcmp(a: []const Limb, b: []const Limb) i8 { |
| 1899 | | @setRuntimeSafety(false); |
| 1906 | @setRuntimeSafety(debug_safety); |
| 1900 | 1907 | const a_len = llnormalize(a); |
| 1901 | 1908 | const b_len = llnormalize(b); |
| 1902 | 1909 | if (a_len < b_len) { |
| ... | ... | @@ -1923,12 +1930,12 @@ pub fn llcmp(a: []const Limb, b: []const Limb) i8 { |
| 1923 | 1930 | } |
| 1924 | 1931 | |
| 1925 | 1932 | fn llmulDigit(acc: []Limb, y: []const Limb, xi: Limb) void { |
| 1926 | | @setRuntimeSafety(false); |
| 1933 | @setRuntimeSafety(debug_safety); |
| 1927 | 1934 | if (xi == 0) { |
| 1928 | 1935 | return; |
| 1929 | 1936 | } |
| 1930 | 1937 | |
| 1931 | | var carry: usize = 0; |
| 1938 | var carry: Limb = 0; |
| 1932 | 1939 | var a_lo = acc[0..y.len]; |
| 1933 | 1940 | var a_hi = acc[y.len..]; |
| 1934 | 1941 | |
| ... | ... | @@ -1945,7 +1952,7 @@ fn llmulDigit(acc: []Limb, y: []const Limb, xi: Limb) void { |
| 1945 | 1952 | |
| 1946 | 1953 | /// returns the min length the limb could be. |
| 1947 | 1954 | fn llnormalize(a: []const Limb) usize { |
| 1948 | | @setRuntimeSafety(false); |
| 1955 | @setRuntimeSafety(debug_safety); |
| 1949 | 1956 | var j = a.len; |
| 1950 | 1957 | while (j > 0) : (j -= 1) { |
| 1951 | 1958 | if (a[j - 1] != 0) { |
| ... | ... | @@ -1959,7 +1966,7 @@ fn llnormalize(a: []const Limb) usize { |
| 1959 | 1966 | |
| 1960 | 1967 | /// Knuth 4.3.1, Algorithm S. |
| 1961 | 1968 | fn llsub(r: []Limb, a: []const Limb, b: []const Limb) void { |
| 1962 | | @setRuntimeSafety(false); |
| 1969 | @setRuntimeSafety(debug_safety); |
| 1963 | 1970 | assert(a.len != 0 and b.len != 0); |
| 1964 | 1971 | assert(a.len > b.len or (a.len == b.len and a[a.len - 1] >= b[b.len - 1])); |
| 1965 | 1972 | assert(r.len >= a.len); |
| ... | ... | @@ -1983,7 +1990,7 @@ fn llsub(r: []Limb, a: []const Limb, b: []const Limb) void { |
| 1983 | 1990 | |
| 1984 | 1991 | /// Knuth 4.3.1, Algorithm A. |
| 1985 | 1992 | fn lladd(r: []Limb, a: []const Limb, b: []const Limb) void { |
| 1986 | | @setRuntimeSafety(false); |
| 1993 | @setRuntimeSafety(debug_safety); |
| 1987 | 1994 | assert(a.len != 0 and b.len != 0); |
| 1988 | 1995 | assert(a.len >= b.len); |
| 1989 | 1996 | assert(r.len >= a.len + 1); |
| ... | ... | @@ -2007,7 +2014,7 @@ fn lladd(r: []Limb, a: []const Limb, b: []const Limb) void { |
| 2007 | 2014 | |
| 2008 | 2015 | /// Knuth 4.3.1, Exercise 16. |
| 2009 | 2016 | fn lldiv1(quo: []Limb, rem: *Limb, a: []const Limb, b: Limb) void { |
| 2010 | | @setRuntimeSafety(false); |
| 2017 | @setRuntimeSafety(debug_safety); |
| 2011 | 2018 | assert(a.len > 1 or a[0] >= b); |
| 2012 | 2019 | assert(quo.len >= a.len); |
| 2013 | 2020 | |
| ... | ... | @@ -2033,7 +2040,7 @@ fn lldiv1(quo: []Limb, rem: *Limb, a: []const Limb, b: Limb) void { |
| 2033 | 2040 | } |
| 2034 | 2041 | |
| 2035 | 2042 | fn llshl(r: []Limb, a: []const Limb, shift: usize) void { |
| 2036 | | @setRuntimeSafety(false); |
| 2043 | @setRuntimeSafety(debug_safety); |
| 2037 | 2044 | assert(a.len >= 1); |
| 2038 | 2045 | assert(r.len >= a.len + (shift / Limb.bit_count) + 1); |
| 2039 | 2046 | |
| ... | ... | @@ -2060,7 +2067,7 @@ fn llshl(r: []Limb, a: []const Limb, shift: usize) void { |
| 2060 | 2067 | } |
| 2061 | 2068 | |
| 2062 | 2069 | fn llshr(r: []Limb, a: []const Limb, shift: usize) void { |
| 2063 | | @setRuntimeSafety(false); |
| 2070 | @setRuntimeSafety(debug_safety); |
| 2064 | 2071 | assert(a.len >= 1); |
| 2065 | 2072 | assert(r.len >= a.len - (shift / Limb.bit_count)); |
| 2066 | 2073 | |
| ... | ... | @@ -2084,7 +2091,7 @@ fn llshr(r: []Limb, a: []const Limb, shift: usize) void { |
| 2084 | 2091 | } |
| 2085 | 2092 | |
| 2086 | 2093 | fn llor(r: []Limb, a: []const Limb, b: []const Limb) void { |
| 2087 | | @setRuntimeSafety(false); |
| 2094 | @setRuntimeSafety(debug_safety); |
| 2088 | 2095 | assert(r.len >= a.len); |
| 2089 | 2096 | assert(a.len >= b.len); |
| 2090 | 2097 | |
| ... | ... | @@ -2098,7 +2105,7 @@ fn llor(r: []Limb, a: []const Limb, b: []const Limb) void { |
| 2098 | 2105 | } |
| 2099 | 2106 | |
| 2100 | 2107 | fn lland(r: []Limb, a: []const Limb, b: []const Limb) void { |
| 2101 | | @setRuntimeSafety(false); |
| 2108 | @setRuntimeSafety(debug_safety); |
| 2102 | 2109 | assert(r.len >= b.len); |
| 2103 | 2110 | assert(a.len >= b.len); |
| 2104 | 2111 | |