Ответ 1
Целые числа (по умолчанию 64-бит) были добавлены в Lua 5.3!
Мне действительно нужно иметь целочисленный тип в 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, но
Я выполнил свою собственную реализацию Integer в C прошлой ночью. Дело в том, что, хотя это улучшение по сравнению с моей наивной реализацией в регулярных lua, а также улучшение над встроенными вызовами в math.floor, это гораздо менее понятно при использовании LuaJIT, где встроенные вызовы по-прежнему являются лотом быстрее, чем реализация C.
Другим решением было бы всегда использовать unboxed numbers и использовать какой-то тип распространения в моем компиляторе для отслеживания целых чисел и при необходимости использовать соответствующие встроенные операции над ними, но сложность этого решения намного больше и побеждает всю цель использования Lua/LuaJIT в качестве бэкэнд.
Я попытаюсь выполнить вашу реализацию, но я сомневаюсь, что это будет лучше, чем встроенные вызовы в LuaJIT. Вполне возможно, что то, что я снимаю (имея как прозрачную работу двойных, так и целых чисел, а также производительность, близкую к встроенным вызовам luaJIT), просто невозможно. Большое вам спасибо за вашу помощь.
@miky: Спасибо, это выглядит красиво, но я сомневаюсь, что смогу исправить его с помощью luaJIT, и если я не смогу, он потеряет все свои промежутки для моей цели.
Целые числа (по умолчанию 64-бит) были добавлены в Lua 5.3!
Зачем они нужны? Лучший способ помочь вам найти эффективное решение вашей проблемы - это понять проблему. Для чего вам нужны целые числа?
Основным штрафным штрафом за то, что я собираю, является (конечно) очень многократное выделение.
Ну, вы создаете замыкания на каждой операции, и я не понимаю, почему у вас есть двойной класс вообще, учитывая, что тип номера 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, представленная в этом сообщении.
Если вы хотите иметь дело только с целыми числами, вы всегда можете #define LUA_NUMBER int
в luaconf.h
.
Вы можете попробовать одну из библиотек произвольной точности, перечисленных в http://www.tecgraf.puc-rio.br/~lhf/ftp/lua/. В частности, lbn является целым и быстрым, но вам нужен OpenSSL. Для простой автономной библиотеки см. lbc.
Вы можете попробовать патч LNUM, он модифицирует ядро Lua для добавления целочисленных числовых типов, таких как 32 и 64 битные целые числа вместе с двойники. Он также поддерживает сложные номера.