| ... | @@ -58,6 +58,11 @@ pub fn calcPowLimbsBufferLen(a_bit_count: usize, y: usize) usize { | ... | @@ -58,6 +58,11 @@ pub fn calcPowLimbsBufferLen(a_bit_count: usize, y: usize) usize { |
| 58 | return 2 + (a_bit_count * y + (limb_bits - 1)) / limb_bits; | 58 | return 2 + (a_bit_count * y + (limb_bits - 1)) / limb_bits; |
| 59 | } | 59 | } |
| 60 | | 60 | |
| | 61 | // Compute the number of limbs required to store a 2s-complement number of `bit_count` bits. |
| | 62 | pub fn calcTwosCompLimbCount(bit_count: usize) usize { |
| | 63 | return std.math.divCeil(usize, bit_count, @bitSizeOf(Limb)) catch unreachable; |
| | 64 | } |
| | 65 | |
| 61 | /// a + b * c + *carry, sets carry to the overflow bits | 66 | /// a + b * c + *carry, sets carry to the overflow bits |
| 62 | pub fn addMulLimbWithCarry(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb { | 67 | pub fn addMulLimbWithCarry(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb { |
| 63 | @setRuntimeSafety(debug_safety); | 68 | @setRuntimeSafety(debug_safety); |
| ... | @@ -980,6 +985,91 @@ pub const Mutable = struct { | ... | @@ -980,6 +985,91 @@ pub const Mutable = struct { |
| 980 | r.normalize(r.len); | 985 | r.normalize(r.len); |
| 981 | } | 986 | } |
| 982 | | 987 | |
| | 988 | /// Truncate an integer to a number of bits, following 2s-complement semantics. |
| | 989 | /// r may alias a. |
| | 990 | /// |
| | 991 | /// Asserts `r` has enough storage to store the result. |
| | 992 | /// The upper bound is `calcTwosCompLimbCount(a.len)`. |
| | 993 | pub fn truncate(r: *Mutable, a: Const, signedness: std.builtin.Signedness, bit_count: usize) void { |
| | 994 | const req_limbs = (bit_count + @bitSizeOf(Limb) - 1) / @bitSizeOf(Limb); |
| | 995 | |
| | 996 | // Handle 0-bit integers. |
| | 997 | if (req_limbs == 0 or a.eqZero()) { |
| | 998 | r.set(0); |
| | 999 | return; |
| | 1000 | } |
| | 1001 | |
| | 1002 | const bit = @truncate(Log2Limb, bit_count - 1); |
| | 1003 | const signmask = @as(Limb, 1) << bit; |
| | 1004 | const mask = (signmask << 1) -% 1; |
| | 1005 | |
| | 1006 | if (!a.positive) { |
| | 1007 | // Convert the integer from sign-magnitude into twos-complement. |
| | 1008 | // -x = ~(x - 1) |
| | 1009 | // Note, we simply take req_limbs * @bitSizeOf(Limb) as the |
| | 1010 | // target bit count. |
| | 1011 | |
| | 1012 | r.addScalar(a.abs(), -1); |
| | 1013 | |
| | 1014 | // Zero-extend the result |
| | 1015 | if (req_limbs > r.len) { |
| | 1016 | mem.set(Limb, r.limbs[r.len .. req_limbs], 0); |
| | 1017 | } |
| | 1018 | |
| | 1019 | // Truncate to required number of limbs. |
| | 1020 | assert(r.limbs.len >= req_limbs); |
| | 1021 | r.len = req_limbs; |
| | 1022 | |
| | 1023 | // Without truncating, we can already peek at the sign bit of the result here. |
| | 1024 | // Note that it will be 0 if the result is negative, as we did not apply the flip here. |
| | 1025 | // If the result is negative, we have |
| | 1026 | // -(-x & mask) |
| | 1027 | // = ~(~(x - 1) & mask) + 1 |
| | 1028 | // = ~(~((x - 1) | ~mask)) + 1 |
| | 1029 | // = ((x - 1) | ~mask)) + 1 |
| | 1030 | // Note, this is only valid for the target bits and not the upper bits |
| | 1031 | // of the most significant limb. Those still need to be cleared. |
| | 1032 | // Also note that `mask` is zero for all other bits, reducing to the identity. |
| | 1033 | // This means that we still need to use & mask to clear off the upper bits. |
| | 1034 | |
| | 1035 | if (signedness == .signed and r.limbs[r.len - 1] & signmask == 0) { |
| | 1036 | // Re-add the one and negate to get the result. |
| | 1037 | r.limbs[r.len - 1] &= mask; |
| | 1038 | // Note, addition cannot require extra limbs here as we did a subtraction before. |
| | 1039 | r.addScalar(r.toConst(), 1); |
| | 1040 | r.normalize(r.len); |
| | 1041 | r.positive = false; |
| | 1042 | } else { |
| | 1043 | llnot(r.limbs[0..r.len]); |
| | 1044 | r.limbs[r.len - 1] &= mask; |
| | 1045 | r.normalize(r.len); |
| | 1046 | } |
| | 1047 | } else { |
| | 1048 | r.copy(a); |
| | 1049 | if (r.len < req_limbs) { |
| | 1050 | // Integer fits within target bits, no wrapping required. |
| | 1051 | return; |
| | 1052 | } |
| | 1053 | |
| | 1054 | r.len = req_limbs; |
| | 1055 | r.limbs[r.len - 1] &= mask; |
| | 1056 | r.normalize(r.len); |
| | 1057 | |
| | 1058 | if (signedness == .signed and r.limbs[r.len - 1] & signmask != 0) { |
| | 1059 | // Convert 2s-complement back to sign-magnitude. |
| | 1060 | // Sign-extend the upper bits so that they are inverted correctly. |
| | 1061 | r.limbs[r.len - 1] |= ~mask; |
| | 1062 | llnot(r.limbs[0..r.len]); |
| | 1063 | |
| | 1064 | // Note, can only overflow if r holds 0xFFF...F which can only happen if |
| | 1065 | // a holds 0. |
| | 1066 | r.addScalar(r.toConst(), 1); |
| | 1067 | |
| | 1068 | r.positive = false; |
| | 1069 | } |
| | 1070 | } |
| | 1071 | } |
| | 1072 | |
| 983 | /// Normalize a possible sequence of leading zeros. | 1073 | /// Normalize a possible sequence of leading zeros. |
| 984 | /// | 1074 | /// |
| 985 | /// [1, 2, 3, 4, 0] -> [1, 2, 3, 4] | 1075 | /// [1, 2, 3, 4, 0] -> [1, 2, 3, 4] |
| ... | @@ -1941,6 +2031,14 @@ pub const Managed = struct { | ... | @@ -1941,6 +2031,14 @@ pub const Managed = struct { |
| 1941 | rma.setMetadata(rma_mut.positive, rma_mut.len); | 2031 | rma.setMetadata(rma_mut.positive, rma_mut.len); |
| 1942 | } | 2032 | } |
| 1943 | } | 2033 | } |
| | 2034 | |
| | 2035 | // r = truncate(Int(signedness, bit_count), a) |
| | 2036 | pub fn truncate(r: *Managed, a: Const, signedness: std.builtin.Signedness, bit_count: usize) !void { |
| | 2037 | try r.ensureCapacity(calcTwosCompLimbCount(a.limbs.len)); |
| | 2038 | var m = r.toMutable(); |
| | 2039 | m.truncate(a, signedness, bit_count); |
| | 2040 | r.setMetadata(m.positive, m.len); |
| | 2041 | } |
| 1944 | }; | 2042 | }; |
| 1945 | | 2043 | |
| 1946 | /// Knuth 4.3.1, Algorithm M. | 2044 | /// Knuth 4.3.1, Algorithm M. |
| ... | @@ -2270,6 +2368,15 @@ fn llshr(r: []Limb, a: []const Limb, shift: usize) void { | ... | @@ -2270,6 +2368,15 @@ fn llshr(r: []Limb, a: []const Limb, shift: usize) void { |
| 2270 | } | 2368 | } |
| 2271 | } | 2369 | } |
| 2272 | | 2370 | |
| | 2371 | // r = ~r |
| | 2372 | fn llnot(r: []Limb) void { |
| | 2373 | @setRuntimeSafety(debug_safety); |
| | 2374 | |
| | 2375 | for (r) |*elem| { |
| | 2376 | elem.* = ~elem.*; |
| | 2377 | } |
| | 2378 | } |
| | 2379 | |
| 2273 | // r = a | b with 2s complement semantics. | 2380 | // r = a | b with 2s complement semantics. |
| 2274 | // r may alias. | 2381 | // r may alias. |
| 2275 | // a and b must not be 0. | 2382 | // a and b must not be 0. |