我真的需要在Lua中有一个整数类型。
整数类型的意思是定义通常的运算符(/ * + etc)并且表现得像整数的类型,内部表示无关紧要。
用表做这样的事情非常简单,问题是,我试过了,而且性能非常差(当然)。这是我的部分实现:
function num_op(a, b, calc_func)
local atype = pytype(a)
local btype = pytype(b)
local a_val, b_val
a_val = (atype == "Integer" or atype == "Double") and a[1] or a
b_val = (btype == "Integer" or btype == "Double") and b[1] or b
val = calc_func(a_val, b_val)
if atype == "Integer" and btype == "Integer" then
return Integer:create(val)
else
return Double:create(val)
end
end
numeric_mt = {
__add = function(a, b)
return num_op(a, b, function(a,b) return a + b end)
end,
__sub = function(a, b)
return num_op(a, b, function(a,b) return a - b end)
end,
__div = function(a, b)
return num_op(a, b, function(a,b) return a / b end)
end,
__mul = function(a, b)
return num_op(a, b, function(a,b) return a * b end)
end,
__tostring = function(a)
return tostring(a[1])
end
}
-----------------------------
-- Integer type definition --
-----------------------------
Integer = {}
Integer_mt = table.copy(numeric_mt)
Integer_mt["__index"] = Integer
function Integer:create(value)
local new_inst = {math.floor(value)}
setmetatable(new_inst, Integer_mt)
return new_inst
end
function Integer:className()
return "Integer"
end
我收集的主要性能损失是(当然)非常多的分配。 LuaJit能够很好地优化运算符函数,但不能优化元表分配。
有人认为使用自定义c实现和userdata可以做得更好吗?或者是我追求的不可能实现的目标?
注意:我知道 lua没有整数。我也知道我可以使用数学库获得相同的结果。我想要的是使用整数时完整的透明度,除了创建阶段。
编辑:我将在这里添加其他信息,以便所有内容仍然是集中的@Mud:我需要在某种程度上拥有透明混合算术,就像你在python / ruby / etc中一样,但具有最佳性能。我正在使用luaJIT作为编译器的目标,使用常规Lua作为luaJIT不支持的平台的后备。这对性能特征非常重要。
这意味着我希望能够做到这一点:
a = int(5) -- Integer value
b = int(2) -- Another Integer
c = 2 -- Double
d = a / b -- == 2 , integer arithmetics
e = a / c -- == 2.5, floating point arithmetics
我可以达到某一点,上面显示了实现。问题是我对每个数字的操作都在减慢,因为常规数字也是盒装的。我可以用调试库重载数字元素,但是
我昨晚在C中推出了自己的Integer实现。问题是,虽然它比我常规lua中的天真实现有所改进,并且还有对math.floor的内联调用的改进,但在使用LuaJIT时更不清楚,其中内联调用仍然是很多比C实现更快。
另一种解决方案是始终使用未装箱的数字,并在我的编译器中使用某种类型的传播来跟踪整数并在需要时对它们使用适当的内联操作,但这种解决方案的复杂性要大得多,而且有点击败了使用Lua / LuaJIT作为后端的全部目的。
我会尝试你的实现,但我怀疑它会比LuaJIT中的内联调用更好。我可能正在拍摄的内容(具有双重和整数的透明操作,以及接近luaJIT的内联调用的性能)是完全不可能的。非常感谢你的帮助。
@miky:谢谢,这看起来不错,但是我怀疑我可以用它修补luaJIT,如果我不能,它会为我的目标失去所有的利益。
答案 0 :(得分:15)
为什么你需要它们吗?帮助您找到问题的高效解决方案的最佳方法是了解问题。具体到底需要什么?
我收集的主要性能损失是(当然)非常多的分配。
好吧,你正在为每个操作创建闭包,我不明白为什么你有一个Double类,因为Lua的数字类型已经是双重的。你不能做这样的事吗?
Integer = {}
local function val(o) return type(o) == 'number' and o or o[1] end
function Integer.__add(a,b) return Integer:create(val(a) + val(b)) end
function Integer.__sub(a,b) return Integer:create(val(a) - val(b)) end
function Integer.__div(a,b) return Integer:create(val(a) / val(b)) end
function Integer.__mul(a,b) return Integer:create(val(a) * val(b)) end
function Integer:__tostring() return tostring(self[1]) end
function Integer:create(value)
return setmetatable({math.floor(value)}, Integer)
end
-- test
a = Integer:create(15.34)
b = Integer:create(775.34433)
print((a*10/2+b-3)/3*a+b) --> 5005
有人认为使用自定义c实现和userdata可以做得更好吗?
是的,C实现应该更快,因为您不需要为每个Integer创建一个表;您的userdata可能只是int*
。这也消除了floor
电话的需要。
答案 1 :(得分:6)
整数(默认为64位)刚刚添加到Lua 5.3中!
答案 2 :(得分:4)
如果您只想 处理整数,您可以#define LUA_NUMBER int
中始终luaconf.h
。
答案 3 :(得分:2)
您可以尝试http://www.tecgraf.puc-rio.br/~lhf/ftp/lua/中列出的任意精度库之一。特别是,lbn仅为整数且速度快,但您需要OpenSSL。有关简单的独立库,请参阅lbc。
答案 4 :(得分:1)
您可以尝试LNUM补丁,它会修改Lua核心以添加整数数字类型,如32位和64位整数以及双精度数。它还支持复数。