| ... | @@ -346,6 +346,47 @@ pub const Mutable = struct { | ... | @@ -346,6 +346,47 @@ pub const Mutable = struct { |
| 346 | } | 346 | } |
| 347 | } | 347 | } |
| 348 | | 348 | |
| | 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 - b | 390 | /// 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 | } |
| 391 | | 432 | |
| | 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 * b | 486 | /// 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 | } |
| 1132 | | 1226 | |
| | 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 | } |
| 1833 | | 1934 | |
| | 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 - b | 1942 | /// 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 | } |
| 1845 | | 1953 | |
| | 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 * b | 1961 | /// 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 { |
| 2034 | | 2149 | |
| 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); |