2010-12-19 78 views
12

我真的需要在Lua中有一個整數類型。Lua整數類型

我的意思是整數類型是一個類型定義通常的操作符(/ * +等)和行爲像一個整數,內部表示並不重要。

用桌子做這樣的事情很簡單,問題是,我嘗試過,而且表現非常差(當然)。這是我的部分實現:

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能夠很好地優化運算符功能,但不能實現metatables分配。

難道有人認爲使用自定義c實現和userdata可以做得更好嗎?或者是我追求不可能達到的目標?

注:i 知道 lua沒有整數。我也知道,我可以使用數學庫獲得相同的結果。我想要的是完整使用整數時的透明度,除了創建階段。

編輯:我會在這裏添加額外的信息,以便一切仍是集中

@Mud:我需要,在一定程度上有透明混合算術中你在Python具有相同的方式/ ruby​​ /等,但是可能具有最佳性能。我使用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 

我能達到這個到某一點,與實施上述表現。問題在於,我對每個數字的運算速度都很慢,因爲常規數字也被裝箱。我可以超載與調試LIB號的元表,但

  • 我不知道這個功能如何可靠的是在生產高質量的軟件使用
  • 它將數字以來的表現還是慢下來,能夠有一個統一的數字接口,我將不得不使用(數字):get(),這將在任何情況下減緩操作。

我在昨晚的C中推出了自己的Integer實現。問題是,雖然它比普通的lua中我的天真實現有所改進,並且還改進了對math.floor的內聯調用,但使用LuaJIT時的情況並不那麼明顯,在這種情況下,內聯調用仍然是比C更快的批次實現。

另一種解決方案是始終使用unboxed數字,並在我的編譯器中使用某種類型的傳播來跟蹤整數,並在需要時使用適當的內聯操作,但此解決方案的複雜性要大得多,擊敗了使用Lua/LuaJIT作爲後端的全部目的。

我會嘗試你的實現,但我懷疑它會比在LuaJIT中的內聯調用更好。很可能,我所拍攝的內容(既有雙精度和整數的透明操作,又有接近對luaJIT的內聯調用的性能)顯然是不可能的。非常感謝您的幫助。

@miky:謝謝,這看起來不錯,但我懷疑我可以用它補丁luaJIT,如果我不能,它會爲我的目標放鬆所有的Interrest。

+2

是的,這是真的,想用什麼來修補LuaJIT是瘋狂,它始終是更好地實現純Lua的整個事情(當然,這就是Lua是很好的,它提供的工具.. )。然後LuaJIT將能夠優化它(而不是C函數)。 – 2010-12-21 16:21:23

回答

4

如果你想只有處理整數,你總是可以#define LUA_NUMBER intluaconf.h

14

爲什麼你需要它們嗎?幫助您找到解決問題性能的最佳方法是瞭解問題。你需要什麼特別的整數?

我收集的主要性能損失是(當然)非常多的分配。

那麼,你正在爲每個操作創建閉包,而且我不明白爲什麼你有一個Double類,因爲Lua的數字類型已經是double類型了。你不能做這樣的事嗎?

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實現和用戶數據做的更好?

是的,C實現應該更快,因爲您不需要爲每個Integer創建一個表;您的用戶數據可能實際上只是一個int*。這也將消除對floor呼叫的需要。

編輯:我寫了一個test C implementation,它比本文中介紹的Lua實現快了約5倍。

+0

嘿泥,謝謝你的回答,我回答了原始問題 – 2010-12-20 13:04:10

+1

我接受了你的回答,因爲即使它最終沒有解決我的問題,它*也回答了這個問題。雖然luaJIT在使用C庫時回退到解釋器,但最終使用C庫並不是一個好的解決方案。 – 2010-12-21 16:14:06

1

你可以嘗試LNUM補丁,它修改Lua核心以添加整數數字類型,比如32和64位整數以及雙精度。它也支持複數。

+0

自述:「使用補丁不會以任何方式改變Lua的外部行爲」。所以絕對不是我所追求的 – 2010-12-21 16:01:44