#lua #memoization
#lua #запоминание
Вопрос:
Итак, у меня есть этот фрагмент кода, и он такой:
do
local function index(n,m)
return n*(n 1)//2 m
end
local binomtable = {}
function binom3(n,m)
if n<0 or m<0 or m>n then return 0 end
if n=0 or m=0 or m=n then return 1 end
local i = index(n,m)
local v = binomtable[i]
if v then return v end
v = binom3(n-1,m-1) binom3(n-1,m)
binomtable[i] = v
return v
end
end
и я хотел бы знать, что
if v then return v end
означает.
Спасибо!
Комментарии:
1.
if v~=nil then return v end
2.
if v~=nil and v~=false then return v end
3. если он уже вычислил значение для binomtable[i] , то он возвращает это значение, в противном случае он продолжит работу со сценарием и сгенерирует значение для этой позиции таблицы.
4. Вы получили принятый ответ. Поэтому я отменяю редактирование «тестового вопроса».
Ответ №1:
Короткий ответ заключается в том, что if v then return v end
возвращает значение v
, если оно соответствует действительности, то есть, если оно не является ни false
тем, ни nil
другим . В противном случае функция продолжается, вычисляя значение для v
, сохраняя это значение в binomtable
и, наконец, возвращая его. Более интересный вопрос: почему функция делает все это?
В опубликованном коде binom3
это рекурсивная функция. При рекурсивных вызовах v = binom3(n-1,m-1) binom3(n-1,m)
будет много дублирования усилий, что означает много потерянного пространства и времени. Рассмотрим:
binom3(4, 2)
--> binom3(3, 1) binom3(3, 2)
--> binom3(2, 0) binom3(2, 1) binom3(2, 1) binom3(2, 2)
--> 1 binom3(1, 0) binom3(1, 1) binom3(1, 0) binom3(1, 1) 1
Обратите внимание, что во втором сокращении есть два идентичных термина:
binom3(2, 1) binom3(2, 1)
Нет причин вычислять binom3(2, 1)
член дважды, и это означает, что пара терминов:
binom3(1, 0) binom3(1, 1)
также должно быть вычислено дважды, как видно из третьего сокращения. Было бы разумно вычислить binom3(2, 1)
только один раз и сохранить результат для последующего использования в более крупных вычислениях. Когда m
и n
больше, а количество вычислений растет экспоненциально, это становится очень важной проблемой для производительности как с точки зрения требуемого объема памяти, так и с точки зрения требуемого времени.
Опубликованный код использует запоминание для повышения производительности. Когда выполняется вычисление, оно сохраняется в таблице binomtable
. Перед выполнением любых вычислений проводится binomtable
консультация. Сначала v
устанавливается значение binomtable[i]
; если это значение является любым истинным значением (любое целое число является истинным значением в Lua), то это значение просто возвращается без необходимости рекурсивного вычисления. В противном случае, если nil
возвращается значение (т. Е. Значение еще не сохранено для вычисления), функция продолжает рекурсивное вычисление. После завершения вычисления новое значение сохраняется binomtable
для использования в следующий раз, когда оно понадобится. Эта стратегия экономит много потраченных впустую вычислительных усилий и может существенно повлиять на производительность таких рекурсивных алгоритмов.
Ответ №2:
На ваш конкретный вопрос о том, что
if v then return v end
означает, что if v
, переменная, не nil
является или false
должна возвращать значение переменной v и прекращать выполнение этой функции.
--Similar
function myfunc(input)
local MyVar = "I am a string and am not nil!"
if MyVar then
return "hi"
else
return "hello"
end
print("I am not seen because I am unreachable code!")
end
если бы эта функция была вызвана, она всегда возвращала бы «hi» вместо «hello», потому что myVar имеет значение true, потому что оно имеет значение. Также print
приведенная ниже функция, которая никогда не будет вызвана, потому что она прекращает выполнение функции после return
вызова a .
Теперь для вашего случая с кодами он проверяет a table
, чтобы увидеть, есть ли у него определенная запись index
, и если она есть, она возвращает значение.