authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-09-27 03:12:38+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-10-04 11:25:29+02:00
logfdb37743fa48bc1ca41a11148dd5d801e9c3a34e
treebf3ad397e24f4073d88ee91a8096cd79181fa9c6
parenta73369244471cf15ed8eda624e86c435a5df295f

big ints: addWrap, subWrap + fix Managed.truncate allocation size


1 files changed, 116 insertions(+), 1 deletions(-)

lib/std/math/big/int.zig+116-1
...@@ -346,6 +346,47 @@ pub const Mutable = struct {...@@ -346,6 +346,47 @@ pub const Mutable = struct {
346 }346 }
347 }347 }
348348
349 /// r = a + b with 2s-complement wrapping semantics.
350 ///
351 /// r, a and b may be aliases
352 /// Asserts the result fits in `r`. An upper bound on the number of limbs needed by
353 /// r is `calcTwosCompLimbCount(bit_count)`.
354 pub fn addWrap(r: *Mutable, a: Const, b: Const, signedness: std.builtin.Signedness, bit_count: usize) void {
355 const req_limbs = calcTwosCompLimbCount(bit_count);
356
357 // We can ignore the upper bits here, those results will be discarded anyway.
358 const a_limbs = a.limbs[0..math.min(req_limbs, a.limbs.len)];
359 const b_limbs = b.limbs[0..math.min(req_limbs, b.limbs.len)];
360
361 if (a.eqZero()) {
362 r.copy(b);
363 } else if (b.eqZero()) {
364 r.copy(a);
365 } else if (a.positive != b.positive) {
366 if (a.positive) {
367 // (a) + (-b) => a - b
368 r.subWrap(a, b.abs(), signedness, bit_count);
369 } else {
370 // (-a) + (b) => b - a
371 r.subWrap(b, a.abs(), signedness, bit_count);
372 }
373 // Don't need to truncate, subWrap does that for us.
374 return;
375 } else {
376 if (a_limbs.len >= b_limbs.len) {
377 _ = lladdcarry(r.limbs, a_limbs, b_limbs);
378 r.normalize(a_limbs.len);
379 } else {
380 _ = lladdcarry(r.limbs, b_limbs, b_limbs);
381 r.normalize(b_limbs.len);
382 }
383
384 r.positive = a.positive;
385 }
386
387 r.truncate(r.toConst(), signedness, bit_count);
388 }
389
349 /// r = a - b390 /// r = a - b
350 ///391 ///
351 /// r, a and b may be aliases.392 /// r, a and b may be aliases.
...@@ -389,6 +430,59 @@ pub const Mutable = struct {...@@ -389,6 +430,59 @@ pub const Mutable = struct {
389 }430 }
390 }431 }
391432
433 /// r = a - b with 2s-complement wrapping semantics.
434 ///
435 /// r, a and b may be aliases
436 /// Asserts the result fits in `r`. An upper bound on the number of limbs needed by
437 /// r is `calcTwosCompLimbCount(bit_count)`.
438 pub fn subWrap(r: *Mutable, a: Const, b: Const, signedness: std.builtin.Signedness, bit_count: usize) void {
439 const req_limbs = calcTwosCompLimbCount(bit_count);
440
441 // We can ignore the upper bits here, those results will be discarded anyway.
442 // We also don't need to mind order here. Again, overflow is ignored here.
443 const a_limbs = a.limbs[0..math.min(req_limbs, a.limbs.len)];
444 const b_limbs = b.limbs[0..math.min(req_limbs, b.limbs.len)];
445
446 if (a.positive != b.positive) {
447 if (a.positive) {
448 // (a) - (-b) => a + b
449 r.addWrap(a, b.abs(), signedness, bit_count);
450 } else {
451 // (-a) - (b) => -a + -b
452 // Note, we don't do -(a + b) here to avoid a second truncate.
453 r.addWrap(a, b.negate(), signedness, bit_count);
454 }
455 // Don't need to truncate, addWrap does that for us.
456 return;
457 } else if (a.positive) {
458 if (a_limbs.len >= b_limbs.len) {
459 // (a) - (b) => a - b
460 _ = llsubcarry(r.limbs, a_limbs, b_limbs);
461 r.normalize(a_limbs.len);
462 r.positive = true;
463 } else {
464 // (a) - (b) => -b + a => -(b - a)
465 _ = llsubcarry(r.limbs, b_limbs, a_limbs);
466 r.normalize(b_limbs.len);
467 r.positive = false;
468 }
469 } else {
470 if (a_limbs.len >= b_limbs.len) {
471 // (-a) - (-b) => -(a - b)
472 _ = llsubcarry(r.limbs, a_limbs, b_limbs);
473 r.normalize(a_limbs.len);
474 r.positive = false;
475 } else {
476 // (-a) - (-b) => --b + -a => b - a
477 _ = llsubcarry(r.limbs, b_limbs, a_limbs);
478 r.normalize(b_limbs.len);
479 r.positive = true;
480 }
481 }
482
483 r.truncate(r.toConst(), signedness, bit_count);
484 }
485
392 /// rma = a * b486 /// rma = a * b
393 ///487 ///
394 /// `rma` may alias with `a` or `b`.488 /// `rma` may alias with `a` or `b`.
...@@ -1130,6 +1224,13 @@ pub const Const = struct {...@@ -1130,6 +1224,13 @@ pub const Const = struct {
1130 };1224 };
1131 }1225 }
11321226
1227 pub fn negate(self: Const) Const {
1228 return .{
1229 .limbs = self.limbs,
1230 .positive = !self.positive,
1231 };
1232 }
1233
1133 pub fn isOdd(self: Const) bool {1234 pub fn isOdd(self: Const) bool {
1134 return self.limbs[0] & 1 != 0;1235 return self.limbs[0] & 1 != 0;
1135 }1236 }
...@@ -1831,6 +1932,13 @@ pub const Managed = struct {...@@ -1831,6 +1932,13 @@ pub const Managed = struct {
1831 r.setMetadata(m.positive, m.len);1932 r.setMetadata(m.positive, m.len);
1832 }1933 }
18331934
1935 pub fn addWrap(r: *Managed, a: Const, b: Const, signedness: std.builtin.Signedness, bit_count: usize) Allocator.Error!void {
1936 try r.ensureCapacity(calcTwosCompLimbCount(bit_count));
1937 var m = r.toMutable();
1938 m.addWrap(a, b, signedness, bit_count);
1939 r.setMetadata(m.positive, m.len);
1940 }
1941
1834 /// r = a - b1942 /// r = a - b
1835 ///1943 ///
1836 /// r, a and b may be aliases.1944 /// r, a and b may be aliases.
...@@ -1843,6 +1951,13 @@ pub const Managed = struct {...@@ -1843,6 +1951,13 @@ pub const Managed = struct {
1843 r.setMetadata(m.positive, m.len);1951 r.setMetadata(m.positive, m.len);
1844 }1952 }
18451953
1954 pub fn subWrap(r: *Managed, a: Const, b: Const, signedness: std.builtin.Signedness, bit_count: usize) Allocator.Error!void {
1955 try r.ensureCapacity(calcTwosCompLimbCount(bit_count));
1956 var m = r.toMutable();
1957 m.subWrap(a, b, signedness, bit_count);
1958 r.setMetadata(m.positive, m.len);
1959 }
1960
1846 /// rma = a * b1961 /// rma = a * b
1847 ///1962 ///
1848 /// rma, a and b may be aliases. However, it is more efficient if rma does not alias a or b.1963 /// rma, a and b may be aliases. However, it is more efficient if rma does not alias a or b.
...@@ -2034,7 +2149,7 @@ pub const Managed = struct {...@@ -2034,7 +2149,7 @@ pub const Managed = struct {
20342149
2035 // r = truncate(Int(signedness, bit_count), a)2150 // r = truncate(Int(signedness, bit_count), a)
2036 pub fn truncate(r: *Managed, a: Const, signedness: std.builtin.Signedness, bit_count: usize) !void {2151 pub fn truncate(r: *Managed, a: Const, signedness: std.builtin.Signedness, bit_count: usize) !void {
2037 try r.ensureCapacity(calcTwosCompLimbCount(a.limbs.len));2152 try r.ensureCapacity(calcTwosCompLimbCount(bit_count));
2038 var m = r.toMutable();2153 var m = r.toMutable();
2039 m.truncate(a, signedness, bit_count);2154 m.truncate(a, signedness, bit_count);
2040 r.setMetadata(m.positive, m.len);2155 r.setMetadata(m.positive, m.len);