Lua Integer тип - PullRequest
       7

Lua Integer тип

14 голосов
/ 19 декабря 2010

Мне действительно нужно иметь целочисленный тип в 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 способен довольно хорошо оптимизировать функции операторов, но не выделяет метатаблицы.

Кто-нибудь думает, что можно было бы добиться большего успеха с помощью пользовательской реализации c и пользовательских данных? Или то, что я преследую, невозможно достичь?

NB: я знаю, у 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

Я могу достичь этого до определенного момента, с реализацией, показанной выше. Проблема в том, что я замедляю операции с каждым числом, так как обычные числа тоже упакованы. Я мог бы перегружать метатаблицу чисел отладочной библиотекой, но

  • Я не знаю, насколько надежна эта функция для использования в программном обеспечении качества производства
  • Это все равно будет замедлять работу чисел, поскольку, чтобы иметь единый интерфейс с числами, я должен буду использовать (number): get (), который в любом случае замедлит работу.

Прошлой ночью я развернул свою собственную реализацию Integer. Дело в том, что, хотя это улучшение по сравнению с моей наивной реализацией в обычном lua, а также улучшение по сравнению со встроенными вызовами math.floor, это гораздо менее очевидно при использовании LuaJIT, где встроенные вызовы по-прежнему lot быстрее, чем реализация C.

Другим решением было бы всегда использовать распакованные числа и использовать какое-то распространение типа в моем компиляторе для отслеживания целых чисел и при необходимости использовать правильные встроенные операции над ними, но сложность этого решения намного больше, и вроде побеждает всю цель использования Lua / LuaJIT в качестве бэкэнда.

Я попробую вашу реализацию, но я сомневаюсь, что это будет лучше, чем встроенные вызовы в LuaJIT. Вполне возможно, что то, для чего я стреляю (имея прозрачную операцию двойных и целых чисел и производительность, близкую к встроенным вызовам в luaJIT), просто невозможно. Большое спасибо за вашу помощь.

@ miky: Спасибо, это выглядит неплохо, но я сомневаюсь, что смогу исправить с ним luaJIT, и если я не смогу, он потеряет весь свой интерес для моей цели.

Ответы [ 5 ]

15 голосов
/ 20 декабря 2010

Зачем они вам нужны?Лучший способ помочь вам найти эффективное решение вашей проблемы - это понять проблему.Для чего конкретно вам нужны целые числа?

Основное снижение производительности из того, что я получаю, - это (конечно) очень многочисленные распределения.

Ну, вы создаетезамыкания на каждую операцию, и я не понимаю, почему у вас вообще есть класс 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.

РЕДАКТИРОВАТЬ: я написал реализацию теста C , и она примерно в 5 раз быстрее, чем реализация Lua, представленная в этом посте.

6 голосов
/ 12 января 2015

Целые числа (64-разрядные по умолчанию) были добавлены в Lua 5.3!

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

4 голосов
/ 20 декабря 2010

Если вы хотите только иметь дело с целыми числами, вы всегда можете #define LUA_NUMBER int в luaconf.h.

2 голосов
/ 20 декабря 2010

Вы можете попробовать одну из библиотек произвольной точности, перечисленных в http://www.tecgraf.puc -rio.br / ~ lhf / ftp / lua / . В частности, lbn является только целочисленным и быстрым, но вам нужен OpenSSL. Для простой автономной библиотеки см. lbc .

1 голос
/ 20 декабря 2010

Вы можете попробовать патч LNUM , он модифицирует ядро ​​Lua для добавления целочисленных числовых типов, таких как 32- и 64-битные целые числа вместе с двойными. Он также поддерживает комплексные числа.

...