Подтвердить что ты не робот

Тип Lua Integer

Мне действительно нужно иметь целочисленный тип в 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-реализацией и userdata? Или это то, чего я преследую невозможным?

NB: я know lua не имеет целых чисел. Я также знаю, что я могу получить те же результаты, используя математику lib. Я хочу получить полную прозрачность при использовании целых чисел, за исключением фазы создания.

EDIT: я собираюсь добавить дополнительную информацию здесь, чтобы все по-прежнему было централизовано

@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

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

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

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

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

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

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

4b9b3361

Ответ 2

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

Основным штрафным штрафом за то, что я собираю, является (конечно) очень многократное выделение.

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

Да, реализация C должна быть быстрее, потому что вам не нужно создавать таблицу для каждого целого; ваши userdata могут буквально быть int*. Это также устранит необходимость вызова floor.

EDIT: я написал сценарий test C, и он ~ в 5 раз быстрее, чем реализация Lua, представленная в этом сообщении.

Ответ 3

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

Ответ 4

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

Ответ 5

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