Lua entier type

j'ai vraiment besoin d'avoir un type entier en Lua.

ce que je veux dire par type entier est un type qui définit les opérateurs habituels (/ * + etc) et qui se comporte comme un entier, la représentation interne n'a pas d'importance.

faire une telle chose avec des tables est très simple, le problème est, j'ai essayé cela, et la performance est terriblement pauvre (bien sûr). Voici mon implémentation partielle:

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 principale pénalité de performance d'après ce que j'ai compris est (bien sûr) les très nombreuses affectations. LuaJit est capable d'optimiser les fonctions des opérateurs assez bien, mais pas les allocations métatables.

quelqu'un pense-t-il qu'il serait possible de faire mieux avec une implémentation C personnalisée et userdata ? Ou est-ce que ce que je cherche est impossible à atteindre ?

NB : je lua n'a pas d'entiers. Je sais aussi que je peux obtenir les mêmes résultats en utilisant la lib math. Est ce que je veux complet transparence lors de l'utilisation entiers, sauf pour la phase de création.

EDIT: je vais ajouter des informations supplémentaires ici pour que tout soit toujours centralisé

@Mud: j'ai besoin, dans une certaine mesure, d'avoir transparent vous avez mélangé l'arithmétique de la même façon que vous avez en python/ruby/etc, mais avec la meilleure performance possible. J'utilise luaJIT comme cible pour un compilateur, avec Lua comme repli pour les plateformes non supportées par luaJIT. Ceci est très important pour la caractéristiques de performance.

<!-Cela signifie que je voudrais pouvoir faire ceci:

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

je peux y arriver jusqu'à un certain point, avec l'implémentation montrée ci-dessus. Le problème est que je ralentis les opérations sur tous les numéros, puisque les numéros réguliers sont boxe aussi. J'ai pu la surcharge de la métatable de nombres avec le debug lib, mais

  • je ne sais pas quelle est la fiabilité de cette fonctionnalité est pour l'utilisation dans la production de logiciels de qualité
  • il sera toujours ralentir la performance des nombres puisque, pour pouvoir avoir une interface unifiée avec les nombres, je vais devoir utiliser (number):get(), ce qui ralentira le fonctionnement dans tous les cas.

j'ai lancé ma propre implémentation Integer en C hier soir. Le fait est, bien qu'il s'agisse d'une amélioration par rapport à mon implémentation naïve dans le lua régulier, et aussi et l'amélioration par rapport aux appels en ligne à des mathématiques.sol, il est beaucoup moins clair en utilisant LuaJIT, où les appels en ligne sont encore beaucoup plus rapide que L'implémentation C.

une autre solution serait d'utiliser toujours des nombres non-encadrés, et d'utiliser une sorte de propagation de type dans mon compilateur pour suivre des entiers et utiliser des opérations en ligne appropriées sur eux quand c'est nécessaire, mais la complexité de cette solution est beaucoup plus grande, et va à l'encontre du but de L'utilisation de Lua/LuaJIT comme un backend.

je vais essayer votre implémentation, mais je doute que ce soit mieux que les appels inline à LuaJIT. Il peut très bien que ce que je tire pour (avoir à la fois le fonctionnement transparent de double et entiers, et la performance proche des appels en ligne sur luaJIT) est tout à fait impossible. Merci beaucoup pour votre aide.

@miky: merci, ça a l'air sympa, mais je doute que je puisse y mettre luaJIT, et si Je ne peux pas, il perd tout son interest pour mon but.

14
demandé sur raph.amiard 2010-12-19 21:29:37

5 réponses

des entiers (64 bits par défaut) viennent d'être ajoutés dans Lua 5.3!

http://www.lua.org/versions.html#5.3

6
répondu user2677280 2015-01-12 17:39:02

Pourquoi avez-vous besoin? La meilleure façon de vous aider à trouver un performant solution à votre problème est de comprendre le problème. Pour quoi précisément avez-vous besoin des entiers?

la principale pénalité de rendement d'après ce que j'ai compris est (bien sûr) les allocations très nombreuses.

Eh bien, vous créez des fermetures sur chaque opération, et je ne comprends pas pourquoi vous avez une classe Double du tout, étant donné que le type de numéro de Lua est déjà un double. Ne pourriez-vous pas faire quelque chose comme cela?

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

Quelqu'un pense qu'il serait possible de faire mieux avec une implémentation C personnalisée et userdata?

Oui, C la mise en œuvre devrait être plus rapide, parce que vous n'avez pas besoin de créer une table pour chaque Entier; votre userdata pourrait littéralement être juste un int*. Cela éliminerait également le besoin defloor appel.

EDIT: j'ai écrit un tester l'implémentation C et c'est ~5 fois plus rapide que L'implémentation Lua présentée dans ce post.

15
répondu Mud 2010-12-20 08:58:17

Si vous voulez traiter avec des entiers que vous pourriez toujours #define LUA_NUMBER intluaconf.h.

4
répondu Zack The Human 2010-12-19 22:26:21

vous pouvez essayer l'une des bibliothèques de précision arbitraires listées à http://www.tecgraf.puc-rio.br / ~lhf / ftp / lua/