ソースを参照

Create primes.lua

blueloveTH 2 年 前
コミット
3d332a694f
1 ファイル変更168 行追加0 行削除
  1. 168 0
      benchmarks/primes.lua

+ 168 - 0
benchmarks/primes.lua

@@ -0,0 +1,168 @@
+local UPPER_BOUND = 5000000
+local PREFIX = 32338
+
+local Node = {}
+function Node:new()
+    local obj = {}
+    setmetatable(obj, self)
+    self.__index = self
+    obj.children = {}
+    obj.terminal = false
+    return obj
+end
+
+local Sieve = {}
+function Sieve:new(limit)
+    local obj = {}
+    setmetatable(obj, self)
+    self.__index = self
+    obj.limit = limit
+    obj.prime = {}
+    for i = 0, limit do
+        obj.prime[i] = false
+    end
+    return obj
+end
+
+function Sieve:to_list()
+    local result = {2, 3}
+    for p = 5, self.limit do
+        if self.prime[p] then
+            table.insert(result, p)
+        end
+    end
+    return result
+end
+
+function Sieve:omit_squares()
+    local r = 5
+    while r * r < self.limit do
+        if self.prime[r] then
+            local i = r * r
+            while i < self.limit do
+                self.prime[i] = false
+                i = i + r * r
+            end
+        end
+        r = r + 1
+    end
+    return self
+end
+
+function Sieve:step1(x, y)
+    local n = (4 * x * x) + (y * y)
+    if n <= self.limit and (n % 12 == 1 or n % 12 == 5) then
+        self.prime[n] = not self.prime[n]
+    end
+end
+
+function Sieve:step2(x, y)
+    local n = (3 * x * x) + (y * y)
+    if n <= self.limit and n % 12 == 7 then
+        self.prime[n] = not self.prime[n]
+    end
+end
+
+function Sieve:step3(x, y)
+    local n = (3 * x * x) - (y * y)
+    if x > y and n <= self.limit and n % 12 == 11 then
+        self.prime[n] = not self.prime[n]
+    end
+end
+
+function Sieve:loop_y(x)
+    local y = 1
+    while y * y < self.limit do
+        self:step1(x, y)
+        self:step2(x, y)
+        self:step3(x, y)
+        y = y + 1
+    end
+end
+
+function Sieve:loop_x()
+    local x = 1
+    while x * x < self.limit do
+        self:loop_y(x)
+        x = x + 1
+    end
+end
+
+function Sieve:calc()
+    self:loop_x()
+    return self:omit_squares()
+end
+
+local function generate_trie(l)
+    local root = Node:new()
+    for _, el in ipairs(l) do
+        local head = root
+        -- attempt to call a nil value (method 'split')
+        -- how to fix? use string.split
+        el = tostring(el)
+        for i=1, #el do
+            local ch = el:sub(i, i)
+            if not head.children[ch] then
+                head.children[ch] = Node:new()
+            end
+            head = head.children[ch]
+        end
+        head.terminal = true
+    end
+    return root
+end
+
+local function find(upper_bound, prefix_)
+    local primes = Sieve:new(upper_bound):calc()
+    local str_prefix = tostring(prefix_)
+    local head = generate_trie(primes:to_list())
+    for i=1, #str_prefix do
+        local ch = str_prefix:sub(i, i)
+        head = head.children[ch]
+        if head == nil then
+            return nil
+        end
+    end
+
+    local queue, result = {{head, str_prefix}}, {}
+    while #queue > 0 do
+        local tuple = table.remove(queue)
+        local top, prefix = tuple[1], tuple[2]
+        if top.terminal then
+            table.insert(result, tonumber(prefix))
+        end
+        for ch, v in pairs(top.children) do
+            table.insert(queue, 1, {v, prefix .. ch})
+        end
+    end
+
+    table.sort(result)
+    return result
+end
+
+local function verify()
+    local left = {2, 23, 29}
+    local right = find(100, 2)
+    if #left ~= #right then
+        print("length not equal")
+        os.exit(1)
+    end
+    for i, v in ipairs(left) do
+        if v ~= right[i] then
+            print(string.format("%s != %s", v, right[i]))
+            os.exit(1)
+        end
+    end
+end
+
+verify()
+local results = find(UPPER_BOUND, PREFIX)
+local expected = {323381, 323383, 3233803, 3233809, 3233851, 3233863, 3233873, 3233887, 3233897}
+
+for i, v in ipairs(results) do
+    if v ~= expected[i] then
+        print(string.format("%s != %s", v, expected[i]))
+        os.exit(1)
+    end
+end
+