NScripter&Luaで素数

素数の求め方。 - 永字八法の続き。
手慰みで。素数なんて、一体何度作られた車輪のことか。
いやまあ、わざわざLuaで作りなおさなくても、LuaからCのライブラリ読み込んでもいいんだろうけどさ。

system.lua

local prime_table = {}
prime_table[1] = 2
prime_table[2] = 3
local prime_table_len = 2
-- 素数列のn番目を返す。
function prime(n)
	local nn = math.floor(n)
	if nn < 1 then return 2 end
	while ( prime_table[nn] == nil ) do
		add_prime()
	end
	return prime_table[nn]
end
-- 与えられた数値の次の素数を返す。
function next_prime(n)
	if n < 2 then return 2 end
	local count = prime_table_len
	local res = prime_table[count]
	if res > n then
		-- 既存の素数を探す
		while ( prime_table[count] > n ) do
			count = count - 1
		end
		res = prime_table[count+1]
	else
		-- 新規素数を作成する。
		while ( res <= n ) do
			res = add_prime()
		end
	end
	return res
end

-- 次の素数を配列に加える。加えた素数を返す。
function add_prime()
	local last_prime = prime_table[prime_table_len] + 2
	while ( is_prime(last_prime) == false ) do
		last_prime = last_prime + 2
	end
	table.insert(prime_table, last_prime)
	prime_table_len = prime_table_len + 1
	return last_prime
end

-- その数値が素数であればtrueを、そうでなければfalseを返す。
function is_prime(n)
	local nn = math.floor(n)
	if nn < 2 then return false end
	if nn < 4 then return true end
	local count = 1
	local res = true
	local prime = 0
	local prime_square = 0
	while ( 1 == 1 ) do
		prime = prime_table[count]
		prime_square = prime * prime
		if prime_square == nn then return false end
		if prime_square > nn then do break end end
		if nn % prime == 0 then
			res = false
			do break end
		end
		count = count + 1
	end
	return res
end

function NSCOM_prime()
	local res = NSPopIntRef()
	NSPopComma()
	NSSetIntValue(res, prime(NSPopInt()))
end

function NSCOM_next_prime()
	local res = NSPopIntRef()
	NSPopComma()
	NSSetIntValue(res, next_prime(NSPopInt()))
end

導入

define節に以下の2行を加える。

luasub prime
luasub next_prime

使い方

prime %0,%1
素数列の1から数えて%1番目の素数を%0に格納する。
next_prime %0,%1
%1よりも大きな素数を%0に格納する。

感想

LuaNScripterと違ってgotoとかがないから、全部whileとかrepeatとかでループを解決しなくちゃいけない。
continueもないし、breakは好きなところにおけないし。*1
やはりgotoは使い方さえ間違えなければ強力な命令なのだなあと納得。もっとも、NScripterではgotoよりもskipやjumpf/jumpbの方が使いやすいんだけども。
後、math.int()がないのを忘れてそこでひっかかってちょっと悩んだ。math.floor()かmath.ceil()を使わないと。

*1:breakは、ブロックの最後にしか置けないと言うルールがある。好きなところに置くためには、"do break end"としなければならない。これはリファレンスでも推奨されているイディオム。