mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 22:35:24 +00:00
std.math.big: add and update tests
This commit is contained in:
parent
b08924e938
commit
c813b6a900
@ -3275,6 +3275,8 @@ const AccOp = enum {
|
||||
fn llmulacc(comptime op: AccOp, opt_allocator: ?Allocator, r: []Limb, a: []const Limb, b: []const Limb) void {
|
||||
assert(r.len >= a.len);
|
||||
assert(r.len >= b.len);
|
||||
assert(!slicesOverlap(r, a));
|
||||
assert(!slicesOverlap(r, b));
|
||||
|
||||
// Order greatest first.
|
||||
var x = a;
|
||||
@ -3313,6 +3315,8 @@ fn llmulaccKaratsuba(
|
||||
) error{OutOfMemory}!void {
|
||||
assert(r.len >= a.len);
|
||||
assert(a.len >= b.len);
|
||||
assert(!slicesOverlap(r, a));
|
||||
assert(!slicesOverlap(r, b));
|
||||
|
||||
// Classical karatsuba algorithm:
|
||||
// a = a1 * B + a0
|
||||
@ -4129,6 +4133,7 @@ fn llsignedxor(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_
|
||||
fn llsquareBasecase(r: []Limb, x: []const Limb) void {
|
||||
const x_norm = x;
|
||||
assert(r.len >= 2 * x_norm.len + 1);
|
||||
assert(!slicesOverlap(r, x));
|
||||
|
||||
// Compute the square of a N-limb bigint with only (N^2 + N)/2
|
||||
// multiplications by exploiting the symmetry of the coefficients around the
|
||||
@ -4224,6 +4229,318 @@ fn fixedIntFromSignedDoubleLimb(A: SignedDoubleLimb, storage: []Limb) Mutable {
|
||||
};
|
||||
}
|
||||
|
||||
fn slicesOverlap(a: []const Limb, b: []const Limb) bool {
|
||||
// there is no overlap if a.ptr + a.len <= b.ptr or b.ptr + b.len <= a.ptr
|
||||
return @intFromPtr(a.ptr + a.len) > @intFromPtr(b.ptr) and @intFromPtr(b.ptr + b.len) > @intFromPtr(a.ptr);
|
||||
}
|
||||
|
||||
test {
|
||||
_ = @import("int_test.zig");
|
||||
}
|
||||
|
||||
const testing_allocator = std.testing.allocator;
|
||||
test "llshl shift by whole number of limb" {
|
||||
const padding = std.math.maxInt(Limb);
|
||||
|
||||
var r: [10]Limb = @splat(padding);
|
||||
|
||||
// arbitrary numbers known to fit ?
|
||||
const A: Limb = @truncate(0xCCCCCCCCCCCCCCCCCCCCCCC);
|
||||
const B: Limb = @truncate(0x22222222222222222222222);
|
||||
|
||||
const data = [2]Limb{ A, B };
|
||||
for (0..9) |i| {
|
||||
@memset(&r, padding);
|
||||
const len = llshl(&r, &data, i * @bitSizeOf(Limb));
|
||||
|
||||
try std.testing.expectEqual(i + 2, len);
|
||||
try std.testing.expectEqualSlices(Limb, &data, r[i .. i + 2]);
|
||||
for (r[0..i]) |x|
|
||||
try std.testing.expectEqual(0, x);
|
||||
for (r[i + 2 ..]) |x|
|
||||
try std.testing.expectEqual(padding, x);
|
||||
}
|
||||
}
|
||||
|
||||
test llshl {
|
||||
if (limb_bits != 64) return error.SkipZigTest;
|
||||
|
||||
// 1 << 63
|
||||
const left_one = 0x8000000000000000;
|
||||
const maxint: Limb = 0xFFFFFFFFFFFFFFFF;
|
||||
|
||||
// zig fmt: off
|
||||
const cases: Cases = &.{
|
||||
.{0, &.{0}, &.{0}},
|
||||
.{0, &.{1}, &.{1}},
|
||||
.{0, &.{125484842448}, &.{125484842448}},
|
||||
.{0, &.{0xdeadbeef}, &.{0xdeadbeef}},
|
||||
.{0, &.{maxint}, &.{maxint}},
|
||||
.{0, &.{left_one}, &.{left_one}},
|
||||
.{0, &.{0, 1}, &.{0, 1}},
|
||||
.{0, &.{1, 2}, &.{1, 2}},
|
||||
.{0, &.{left_one, 1}, &.{left_one, 1}},
|
||||
.{1, &.{0}, &.{0}},
|
||||
.{1, &.{2}, &.{1}},
|
||||
.{1, &.{250969684896}, &.{125484842448}},
|
||||
.{1, &.{0x1bd5b7dde}, &.{0xdeadbeef}},
|
||||
.{1, &.{0xfffffffffffffffe, 1}, &.{maxint}},
|
||||
.{1, &.{0, 1}, &.{left_one}},
|
||||
.{1, &.{0, 2}, &.{0, 1}},
|
||||
.{1, &.{2, 4}, &.{1, 2}},
|
||||
.{1, &.{0, 3}, &.{left_one, 1}},
|
||||
.{5, &.{32}, &.{1}},
|
||||
.{5, &.{4015514958336}, &.{125484842448}},
|
||||
.{5, &.{0x1bd5b7dde0}, &.{0xdeadbeef}},
|
||||
.{5, &.{0xffffffffffffffe0, 0x1f}, &.{maxint}},
|
||||
.{5, &.{0, 16}, &.{left_one}},
|
||||
.{5, &.{0, 32}, &.{0, 1}},
|
||||
.{5, &.{32, 64}, &.{1, 2}},
|
||||
.{5, &.{0, 48}, &.{left_one, 1}},
|
||||
.{64, &.{0, 1}, &.{1}},
|
||||
.{64, &.{0, 125484842448}, &.{125484842448}},
|
||||
.{64, &.{0, 0xdeadbeef}, &.{0xdeadbeef}},
|
||||
.{64, &.{0, maxint}, &.{maxint}},
|
||||
.{64, &.{0, left_one}, &.{left_one}},
|
||||
.{64, &.{0, 0, 1}, &.{0, 1}},
|
||||
.{64, &.{0, 1, 2}, &.{1, 2}},
|
||||
.{64, &.{0, left_one, 1}, &.{left_one, 1}},
|
||||
.{35, &.{0x800000000}, &.{1}},
|
||||
.{35, &.{13534986488655118336, 233}, &.{125484842448}},
|
||||
.{35, &.{0xf56df77800000000, 6}, &.{0xdeadbeef}},
|
||||
.{35, &.{0xfffffff800000000, 0x7ffffffff}, &.{maxint}},
|
||||
.{35, &.{0, 17179869184}, &.{left_one}},
|
||||
.{35, &.{0, 0x800000000}, &.{0, 1}},
|
||||
.{35, &.{0x800000000, 0x1000000000}, &.{1, 2}},
|
||||
.{35, &.{0, 0xc00000000}, &.{left_one, 1}},
|
||||
.{70, &.{0, 64}, &.{1}},
|
||||
.{70, &.{0, 8031029916672}, &.{125484842448}},
|
||||
.{70, &.{0, 0x37ab6fbbc0}, &.{0xdeadbeef}},
|
||||
.{70, &.{0, 0xffffffffffffffc0, 63}, &.{maxint}},
|
||||
.{70, &.{0, 0, 32}, &.{left_one}},
|
||||
.{70, &.{0, 0, 64}, &.{0, 1}},
|
||||
.{70, &.{0, 64, 128}, &.{1, 2}},
|
||||
.{70, &.{0, 0, 0x60}, &.{left_one, 1}},
|
||||
};
|
||||
// zig fmt: on
|
||||
|
||||
try test_shift_cases(llshl, cases);
|
||||
try test_shift_cases_aliasing(llshl, cases, -1);
|
||||
}
|
||||
|
||||
test "llshl shift 0" {
|
||||
const n = @bitSizeOf(Limb);
|
||||
if (n <= 20) return error.SkipZigTest;
|
||||
|
||||
// zig fmt: off
|
||||
const cases = &.{
|
||||
.{0, &.{0}, &.{0}},
|
||||
.{1, &.{0}, &.{0}},
|
||||
.{5, &.{0}, &.{0}},
|
||||
.{13, &.{0}, &.{0}},
|
||||
.{20, &.{0}, &.{0}},
|
||||
.{0, &.{0, 0}, &.{0, 0}},
|
||||
.{2, &.{0, 0}, &.{0, 0}},
|
||||
.{7, &.{0, 0}, &.{0, 0}},
|
||||
.{11, &.{0, 0}, &.{0, 0}},
|
||||
.{19, &.{0, 0}, &.{0, 0}},
|
||||
|
||||
.{0, &.{0}, &.{0}},
|
||||
.{n, &.{0, 0}, &.{0}},
|
||||
.{2*n, &.{0, 0, 0}, &.{0}},
|
||||
.{3*n, &.{0, 0, 0, 0}, &.{0}},
|
||||
.{4*n, &.{0, 0, 0, 0, 0}, &.{0}},
|
||||
.{0, &.{0, 0}, &.{0, 0}},
|
||||
.{n, &.{0, 0, 0}, &.{0, 0}},
|
||||
.{2*n, &.{0, 0, 0, 0}, &.{0, 0}},
|
||||
.{3*n, &.{0, 0, 0, 0, 0}, &.{0, 0}},
|
||||
.{4*n, &.{0, 0, 0, 0, 0, 0}, &.{0, 0}},
|
||||
};
|
||||
// zig fmt: on
|
||||
|
||||
try test_shift_cases(llshl, cases);
|
||||
try test_shift_cases_aliasing(llshl, cases, -1);
|
||||
}
|
||||
|
||||
test "llshr shift 0" {
|
||||
const n = @bitSizeOf(Limb);
|
||||
|
||||
// zig fmt: off
|
||||
const cases = &.{
|
||||
.{0, &.{0}, &.{0}},
|
||||
.{1, &.{0}, &.{0}},
|
||||
.{5, &.{0}, &.{0}},
|
||||
.{13, &.{0}, &.{0}},
|
||||
.{20, &.{0}, &.{0}},
|
||||
.{0, &.{0, 0}, &.{0, 0}},
|
||||
.{2, &.{0}, &.{0, 0}},
|
||||
.{7, &.{0}, &.{0, 0}},
|
||||
.{11, &.{0}, &.{0, 0}},
|
||||
.{19, &.{0}, &.{0, 0}},
|
||||
|
||||
.{n, &.{0}, &.{0}},
|
||||
.{2*n, &.{0}, &.{0}},
|
||||
.{3*n, &.{0}, &.{0}},
|
||||
.{4*n, &.{0}, &.{0}},
|
||||
.{n, &.{0}, &.{0, 0}},
|
||||
.{2*n, &.{0}, &.{0, 0}},
|
||||
.{3*n, &.{0}, &.{0, 0}},
|
||||
.{4*n, &.{0}, &.{0, 0}},
|
||||
|
||||
.{1, &.{}, &.{}},
|
||||
.{2, &.{}, &.{}},
|
||||
.{64, &.{}, &.{}},
|
||||
};
|
||||
// zig fmt: on
|
||||
|
||||
try test_shift_cases(llshr, cases);
|
||||
try test_shift_cases_aliasing(llshr, cases, 1);
|
||||
}
|
||||
|
||||
test "llshr to 0" {
|
||||
const n = @bitSizeOf(Limb);
|
||||
if (n != 64 and n != 32) return error.SkipZigTest;
|
||||
|
||||
// zig fmt: off
|
||||
const cases = &.{
|
||||
.{1, &.{0}, &.{0}},
|
||||
.{1, &.{0}, &.{1}},
|
||||
.{5, &.{0}, &.{1}},
|
||||
.{65, &.{0}, &.{0, 1}},
|
||||
.{193, &.{0}, &.{0, 0, std.math.maxInt(Limb)}},
|
||||
.{193, &.{0}, &.{std.math.maxInt(Limb), 1, std.math.maxInt(Limb)}},
|
||||
.{193, &.{0}, &.{0xdeadbeef, 0xabcdefab, 0x1234}},
|
||||
};
|
||||
// zig fmt: on
|
||||
|
||||
try test_shift_cases(llshr, cases);
|
||||
try test_shift_cases_aliasing(llshr, cases, 1);
|
||||
}
|
||||
|
||||
test "llshr single" {
|
||||
if (limb_bits != 64) return error.SkipZigTest;
|
||||
|
||||
// 1 << 63
|
||||
const left_one = 0x8000000000000000;
|
||||
const maxint: Limb = 0xFFFFFFFFFFFFFFFF;
|
||||
|
||||
// zig fmt: off
|
||||
const cases: Cases = &.{
|
||||
.{0, &.{0}, &.{0}},
|
||||
.{0, &.{1}, &.{1}},
|
||||
.{0, &.{125484842448}, &.{125484842448}},
|
||||
.{0, &.{0xdeadbeef}, &.{0xdeadbeef}},
|
||||
.{0, &.{maxint}, &.{maxint}},
|
||||
.{0, &.{left_one}, &.{left_one}},
|
||||
.{1, &.{0}, &.{0}},
|
||||
.{1, &.{1}, &.{2}},
|
||||
.{1, &.{62742421224}, &.{125484842448}},
|
||||
.{1, &.{62742421223}, &.{125484842447}},
|
||||
.{1, &.{0x6f56df77}, &.{0xdeadbeef}},
|
||||
.{1, &.{0x7fffffffffffffff}, &.{maxint}},
|
||||
.{1, &.{0x4000000000000000}, &.{left_one}},
|
||||
.{8, &.{1}, &.{256}},
|
||||
.{8, &.{490175165}, &.{125484842448}},
|
||||
.{8, &.{0xdeadbe}, &.{0xdeadbeef}},
|
||||
.{8, &.{0xffffffffffffff}, &.{maxint}},
|
||||
.{8, &.{0x80000000000000}, &.{left_one}},
|
||||
};
|
||||
// zig fmt: on
|
||||
|
||||
try test_shift_cases(llshr, cases);
|
||||
try test_shift_cases_aliasing(llshr, cases, 1);
|
||||
}
|
||||
|
||||
test llshr {
|
||||
if (limb_bits != 64) return error.SkipZigTest;
|
||||
|
||||
// 1 << 63
|
||||
const left_one = 0x8000000000000000;
|
||||
const maxint: Limb = 0xFFFFFFFFFFFFFFFF;
|
||||
|
||||
// zig fmt: off
|
||||
const cases: Cases = &.{
|
||||
.{0, &.{0, 0}, &.{0, 0}},
|
||||
.{0, &.{0, 1}, &.{0, 1}},
|
||||
.{0, &.{15, 1}, &.{15, 1}},
|
||||
.{0, &.{987656565, 123456789456}, &.{987656565, 123456789456}},
|
||||
.{0, &.{0xfeebdaed, 0xdeadbeef}, &.{0xfeebdaed, 0xdeadbeef}},
|
||||
.{0, &.{1, maxint}, &.{1, maxint}},
|
||||
.{0, &.{0, left_one}, &.{0, left_one}},
|
||||
.{1, &.{0}, &.{0, 0}},
|
||||
.{1, &.{left_one}, &.{0, 1}},
|
||||
.{1, &.{0x8000000000000007}, &.{15, 1}},
|
||||
.{1, &.{493828282, 61728394728}, &.{987656565, 123456789456}},
|
||||
.{1, &.{0x800000007f75ed76, 0x6f56df77}, &.{0xfeebdaed, 0xdeadbeef}},
|
||||
.{1, &.{left_one, 0x7fffffffffffffff}, &.{1, maxint}},
|
||||
.{1, &.{0, 0x4000000000000000}, &.{0, left_one}},
|
||||
.{64, &.{0}, &.{0, 0}},
|
||||
.{64, &.{1}, &.{0, 1}},
|
||||
.{64, &.{1}, &.{15, 1}},
|
||||
.{64, &.{123456789456}, &.{987656565, 123456789456}},
|
||||
.{64, &.{0xdeadbeef}, &.{0xfeebdaed, 0xdeadbeef}},
|
||||
.{64, &.{maxint}, &.{1, maxint}},
|
||||
.{64, &.{left_one}, &.{0, left_one}},
|
||||
.{72, &.{0}, &.{0, 0}},
|
||||
.{72, &.{0}, &.{0, 1}},
|
||||
.{72, &.{0}, &.{15, 1}},
|
||||
.{72, &.{482253083}, &.{987656565, 123456789456}},
|
||||
.{72, &.{0xdeadbe}, &.{0xfeebdaed, 0xdeadbeef}},
|
||||
.{72, &.{0xffffffffffffff}, &.{1, maxint}},
|
||||
.{72, &.{0x80000000000000}, &.{0, left_one}},
|
||||
};
|
||||
// zig fmt: on
|
||||
|
||||
try test_shift_cases(llshr, cases);
|
||||
try test_shift_cases_aliasing(llshr, cases, 1);
|
||||
}
|
||||
|
||||
const Cases = []const struct { usize, []const Limb, []const Limb };
|
||||
fn test_shift_cases(func: fn ([]Limb, []const Limb, usize) usize, cases: Cases) !void {
|
||||
const padding = std.math.maxInt(Limb);
|
||||
var r: [20]Limb = @splat(padding);
|
||||
|
||||
for (cases) |case| {
|
||||
const shift = case[0];
|
||||
const expected = case[1];
|
||||
const data = case[2];
|
||||
|
||||
std.debug.assert(expected.len <= 20);
|
||||
|
||||
@memset(&r, padding);
|
||||
const len = func(&r, data, shift);
|
||||
|
||||
try std.testing.expectEqual(expected.len, len);
|
||||
try std.testing.expectEqualSlices(Limb, expected, r[0..len]);
|
||||
for (r[len..]) |x|
|
||||
try std.testing.expectEqual(padding, x);
|
||||
}
|
||||
}
|
||||
|
||||
fn test_shift_cases_aliasing(func: fn ([]Limb, []const Limb, usize) usize, cases: Cases, shift_direction: isize) !void {
|
||||
const padding = std.math.maxInt(Limb);
|
||||
var r: [60]Limb = @splat(padding);
|
||||
const base = 20;
|
||||
|
||||
assert(shift_direction == 1 or shift_direction == -1);
|
||||
|
||||
for (0..10) |limb_shift| {
|
||||
for (cases) |case| {
|
||||
const shift = case[0];
|
||||
const expected = case[1];
|
||||
const data = case[2];
|
||||
|
||||
std.debug.assert(expected.len <= 20);
|
||||
|
||||
@memset(&r, padding);
|
||||
const final_limb_base: usize = @intCast(base + shift_direction * @as(isize, @intCast(limb_shift)));
|
||||
const written_data = r[final_limb_base..][0..data.len];
|
||||
@memcpy(written_data, data);
|
||||
|
||||
const len = func(r[base..], written_data, shift);
|
||||
|
||||
try std.testing.expectEqual(expected.len, len);
|
||||
try std.testing.expectEqualSlices(Limb, expected, r[base .. base + len]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user