const std = @import("std"); const stdout = std.io.getStdOut().writer(); fn print(comptime str: []const u8, args: anytype) void { stdout.print(str, args) catch unreachable; } fn println(comptime str: []const u8, args: anytype) void { print(str ++ "\n", args); } //const n: u512 = 7405872386298001828045412304885395957447735855540402226273272018863616985100578690399814241980651881616439657049448993379923363875365701026162288146836853; const n: u512 = 70666344586694209770041979947; var sqrt: u512 = undefined; const Pack = struct { const Self = @This(); alloc: std.mem.Allocator, n1: u512, n2: u512, fn init(alloc: std.mem.Allocator, n1: u512, n2: u512) !*Self { const self = try alloc.create(Self); self.n1 = n1; self.n2 = n2; self.alloc = alloc; return self; } fn same(self: *Self, other: *Self) bool { return (self.n1 == other.n1 and self.n2 == other.n2) or (self.n1 == other.n2 and self.n2 == other.n1); } fn sameNumbers(self: *Self, n1: u512, n2: u512) bool { return (self.n1 == n1 and self.n2 == n2); } fn print(self: *Self) void { println("{} {}", .{ self.n1, self.n2 }); } fn deinit(self: *Self) void { self.alloc.destroy(self); } }; const PackList = std.ArrayList(*Pack); fn addPackNumbers(self: *PackList, n1: u512, n2: u512) !void { for (self.items, 0..) |item, j| { var i = item; if (n1 == i.n1) { if (n2 == i.n2) { return; } else if (n2 > i.n2) { var pack = try Pack.init(self.allocator, n1, n2); try self.insert(j + 1, pack); } } if (n1 < i.n1) { var pack = try Pack.init(self.allocator, n1, n2); try self.insert(j, pack); return; } } var pack = try Pack.init(self.allocator, n1, n2); try self.append(pack); } fn base3Mask(val: u512, size: usize) u512 { return val % std.math.pow(u512, 10, size); } var nBase: u512 = undefined; pub fn main() !void { var alloctor = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer alloctor.deinit(); var alloc = alloctor.allocator(); sqrt = std.math.sqrt(n); nBase = base3Mask(n, 1); println("BaseMask {}", .{nBase}); var items = try searchAcc(alloc, 1); var toRemove = std.ArrayList(usize).init(alloc); defer toRemove.deinit(); var cpuCount = try std.Thread.getCpuCount(); var threads = try alloc.alloc(std.Thread, cpuCount); defer alloc.free(threads); var results = try alloc.alloc(PackList, cpuCount); defer alloc.free(results); for (2..512) |acc| { nBase = base3Mask(n, acc); toRemove.clearRetainingCapacity(); println("Stared threaded work on {}", .{acc}); for (0..cpuCount) |id| { threads[id] = try std.Thread.spawn(.{ .stack_size = 1024 * 1024 * 1024, .allocator = alloc, }, threadSearch, .{ items, id, cpuCount, acc, results }); } for (0..cpuCount) |id| { threads[id].join(); } var total: u64 = 0; for (results) |result| { total += result.items.len; } println("Finish threaded work on {} total {}", .{ acc, total }); for (items.items) |item| { item.deinit(); } items.clearRetainingCapacity(); for (results) |result| { //for (result.items) |toAdd| { //try addPack(&newToAdd, toAdd); //} try items.appendSlice(result.items); result.deinit(); } // println("results for {}", .{acc}); // for (items.items) |item| { // item.print(); // } if (acc == 10) { println("For items: {}", .{items.items.len}); for (items.items) |item| { item.print(); } break; } else { println("For finished {}; items: {}", .{ acc, items.items.len }); } } } fn threadSearch(items: PackList, id: usize, threadCount: usize, acc: u64, results: []PackList) !void { const max = @max(items.items.len / threadCount, 1); //var returned = PackList.init(items.allocator); var returned = PackList.init(std.heap.page_allocator); const len = items.items.len; for (0..max) |_i| { var i = id + _i * threadCount; if (i >= len) { break; } var item = items.items[i]; if (!verifyAccuracy(item, acc)) { //println("{} {} does not hold for acc {}", .{ item.n1, item.n2, acc }); try searchPackAcc(&returned, acc, item); } else { try addPackNumbers(&returned, @min(item.n1, item.n2), @max(item.n1, item.n2)); } } results[id] = returned; return; } fn searchPackAcc(packList: *PackList, acc: u64, pack: *Pack) !void { var size_n1: u512 = std.math.pow(u512, 10, std.math.log10_int(pack.n1) + 1); var size_n2: u512 = std.math.pow(u512, 10, std.math.log10_int(pack.n2) + 1); for (0..10) |_i| { var i = _i * size_n1 + pack.n1; for (0..10) |_j| { var j = _j * size_n2 + pack.n2; var mul: u512 = i * j; if (mul == n) { println("Found them {} {}!", .{ j, i }); std.os.exit(1); } if (mul > n) break; var mulMask = base3Mask(mul, acc); if (mulMask == nBase) { try addPackNumbers(packList, @min(i, j), @max(i, j)); } } } } fn searchAcc(alloc: std.mem.Allocator, acc: u64) !PackList { var packList = PackList.init(alloc); for (0..10) |i| { for (0..10) |j| { var mul: u512 = i * j; if (mul > n) break; var mulMask = base3Mask(mul, acc); if (mulMask == nBase) { try addPackNumbers(&packList, @min(i, j), @max(i, j)); } } } return packList; } fn verifyAccuracy(pack: *Pack, acc: u64) bool { var mulMask = base3Mask(pack.n1 * pack.n2, acc); return mulMask == nBase; }