2010-12-19 13 views
12

realmente necesito tener un tipo entero en Lua.Lua Integer tipo

Lo que quiero decir por tipo entero es un tipo que define los operadores habituales (/ * + etc) y que se comporta como un entero, la representación interna no importa.

Hacer tal cosa con las tablas es muy simple, el problema es que lo intenté y el rendimiento es terriblemente pobre (por supuesto). Aquí está mi aplicación parcial:

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 

La pena principal actuación Por lo que sé es (por supuesto) las muy numerosas asignaciones. LuaJit es capaz de optimizar las funciones de los operadores bastante bien, pero no las asignaciones de metatablas.

¿Alguien piensa que sería posible mejorar con una implementación de c personalizada y userdata? ¿O es lo que estoy persiguiendo imposible de alcanzar?

NB: i sabe lua no tiene números enteros. También sé que puedo obtener los mismos resultados usando math lib. Lo que quiero es completar transparencia cuando se usan enteros, a excepción de la fase de creación.

EDIT: Voy a añadir información adicional en aquí para que todo sigue siendo centralizado

@Mud: necesito, hasta cierto punto a tener aritmética mixtos transparentes de la misma manera que usted tiene en pitón/ruby ​​/ etc, pero con el mejor rendimiento posible. Estoy usando luaJIT como objetivo para un compilador, con Lua regular como respaldo para plataformas que no son compatibles con luaJIT. Esto es muy importante para las características de rendimiento.

Significa que me gustaría ser capaz de hacer esto:

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 

que puede llegar a que, hasta cierto punto, con la implementación mostró anteriormente. El problema es que estoy ralentizando las operaciones en cada número, ya que los números regulares también están encasillados. Yo podría sobrecargar el metatabla de números con la lib de depuración, pero

  • no sé qué tan confiable es esta característica para su uso en la producción de software de calidad
  • Será todavía ralentizar el rendimiento de los números, ya que, a ser capaz de tener una interfaz unificada para los números, tendré que usar (número): get(), lo que ralentizará la operación en cualquier caso.

Hice mi propia implementación de entero en C anoche. El caso es que, aunque es una mejora sobre mi implementación ingenua en lua regular, y también y mejora sobre las llamadas en línea a math.floor, es mucho menos claro cuando se usa LuaJIT, donde las llamadas en línea son todavía un lote más rápido que el C implementación.

Otra solución sería utilizar siempre los números sin clasificar, y utilizar algún tipo de propagación en mi compilador para realizar un seguimiento de enteros y usar operaciones en línea adecuadas cuando sea necesario, pero la complejidad de esta solución es mucho mayor, y de derrotas con el propósito de usar Lua/LuaJIT como un back-end.

Voy a probar su implementación, pero dudo que sea mejor que las llamadas en línea en LuaJIT.Es muy posible que lo que estoy filmando (con una operación transparente de números dobles y enteros, y un rendimiento cercano a las llamadas en línea en luaJIT) sea completamente imposible. Muchas gracias por su ayuda.

@miky: Gracias, esto se ve bien, pero dudo que pueda parchar luaJIT con él, y si no puedo, pierde todo su interés por mi objetivo.

+2

Sí, eso es cierto, intentando parchear LuaJIT con cualquier cosa es una locura, es siempre mejor para poner en práctica todo el asunto de pura Lua (bueno, eso es lo que Lua es bueno para, proporciona las herramientas .. .). Entonces LuaJIT podrá optimizarlo (no con funciones C). –

Respuesta

4

Si desea solo tratar con enteros siempre puede #define LUA_NUMBER int en luaconf.h.

14

¿Por qué ¿los necesita? La mejor manera de ayudarlo a encontrar una solución eficaz para su problema es comprender el problema. ¿Para qué necesitas enteros específicamente?

La pena de rendimiento principal de lo que deduzco es (por supuesto) las numerosas asignaciones.

Bueno, está creando cierres en cada operación, y no entiendo por qué tiene una clase doble en absoluto, dado que el tipo de número de Lua ya es un doble. ¿No podrías hacer algo como esto?

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 

Alguien cree que sería posible hacerlo mejor con una implementación personalizada C y los datos de usuario?

Sí, una implementación en C debería ser más rápida, porque no necesitaría crear una tabla para cada Entero; sus datos de usuario podrían ser literalmente int*. Esto también eliminaría la necesidad de la llamada floor.

EDIT: Escribí test C implementation y es ~ 5 veces más rápido que la implementación de Lua presentada en esta publicación.

+0

Hola fango, gracias por tu respuesta, respondí en la pregunta original –

+1

Acepté tu respuesta, porque incluso si al final no resolvió mi problema, * responde * la pregunta. Aunque luaJIT no es compatible con el intérprete cuando usa librerías C, entonces usar una biblioteca C no fue una buena solución al final –

1

Puede probar el parche LNUM, modifica el núcleo de Lua para agregar tipos numéricos enteros, como los enteros de 32 y 64 bits junto con los dobles. También es compatible con números complejos.

+0

Del archivo léame: "Usar el parche NO cambia el comportamiento externo de Lua de ninguna manera". Definitivamente no es lo que busco –