Перейти к содержимому
Zer0Galaxy

Оптимизация округления в Lua

Рекомендуемые сообщения

Это обсуждение было отпочковано от темы Майнинг OpenComputer.

 

local function round(num)
    return num + (2 ^ 52 + 2 ^ 51) - (2 ^ 52 + 2 ^ 51)
end

Вот мне просто интересно, каждый раз при вызове функции двойка будет четыре раза возводиться в степень? Не будет ли эффективнее сделать так?

local huge = 2 ^ 52 + 2 ^ 51
local function round(num)
    return num + huge - huge
end

Да и подход к округлению странный. Чем не устраивает math.floor(num+0.5) ?

 

Зачем для получения timeDifference нужно реальное время? Измерять временнЫе интервалы в OpenOS можно не пропиливая жесткий диск.

 

И самый главный вопрос: откуда будут сыпаться биткойны и много ли уже насыпалось?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
6 часов назад, Zer0Galaxy сказал:

local function round(num)
    return num + (2 ^ 52 + 2 ^ 51) - (2 ^ 52 + 2 ^ 51)
end

Вот мне просто интересно, каждый раз при вызове функции двойка будет четыре раза возводиться в степень? Не будет ли эффективнее сделать так?


local huge = 2 ^ 52 + 2 ^ 51
local function round(num)
    return num + huge - huge
end

Да и подход к округлению странный. Чем не устраивает math.floor(num+0.5) ?

 

Зачем для получения timeDifference нужно реальное время? Измерять временнЫе интервалы в OpenOS можно не пропиливая жесткий диск.

 

И самый главный вопрос: откуда будут сыпаться биткойны и много ли уже насыпалось?

1. Исправлю

2. Исправлю

3. Мы майним Duino-Coin (0.00106335$ прайс) примерно в день будет 3 -5 шт.:beach:

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
10 минут назад, OpenReactor сказал:

Мы майним Duino-Coin (0.00106335$ прайс) примерно в день будет 3 -5 шт.:beach:

На каком сервере уже разрешили майнить?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 минуту назад, eu_tomat сказал:

На каком сервере уже разрешили майнить?

Локальный) И только для теста. Это просто бессмысленно)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
В 28.09.2021 в 12:54, Zer0Galaxy сказал:

Вот мне просто интересно, каждый раз при вызове функции двойка будет четыре раза возводиться в степень? Не будет ли эффективнее сделать так?

Посмотрим на байт-код:

$ echo 'local function round(nul) return nul + (2 ^ 52 + 2 ^ 51) - (2 ^ 52 + 2 ^ 51) end' | luac5.3 -l -l -

main <stdin:0,0> (2 instructions at 0x55f08348ca20)
0+ params, 2 slots, 1 upvalue, 1 local, 0 constants, 1 function
        1       [1]     CLOSURE         0 0     ; 0x55f08348cc60
        2       [1]     RETURN          0 1
constants (0) for 0x55f08348ca20:
locals (1) for 0x55f08348ca20:
        0       round   2       3
upvalues (1) for 0x55f08348ca20:
        0       _ENV    1       0

function <stdin:1,1> (4 instructions at 0x55f08348cc60)
1 param, 2 slots, 0 upvalues, 1 local, 1 constant, 0 functions
        1       [1]     ADD             1 0 -1  ; - 6.7553994410557e+15
        2       [1]     SUB             1 1 -1  ; - 6.7553994410557e+15
        3       [1]     RETURN          1 2
        4       [1]     RETURN          0 1
constants (1) for 0x55f08348cc60:
        1       6.7553994410557e+15
locals (1) for 0x55f08348cc60:
        0       nul     1       5
upvalues (0) for 0x55f08348cc60:

Видно, что ADD и SUB тут работают с константой. Обращение к константе быстрое, доступное, лёгкое, воздушное. В предложенном варианте появляется upvalue, к которым доступ будет дольше. Так что эффективнее не станет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

@Fingercomp Опыт подтверждает твои выводы:

 

local uptime=require("computer").uptime

local function round1(num)
    return num + (2 ^ 52 + 2 ^ 51) - (2 ^ 52 + 2 ^ 51)
end

local huge = 2 ^ 52 + 2 ^ 51
local function round2(num)
    return num + huge - huge
end

n = 1000000

start=uptime()
for i=1,n do
  round1(1.234)
end
print("Constant ",uptime()-start)

start=uptime()
for i=1,n do
  round2(1.234)
end
print("Upvalue ",uptime()-start)

start=uptime()
for i=1,n do
  math.floor(1.234+0.5)
end
print("math.floor ",uptime()-start)

image.png.89b444b504a39a05ced50f1e58f5eeab.png

Предложенный топикстартером вариант эффективнее и моего и floor()

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
50 минут назад, Zer0Galaxy сказал:

Предложенный топикстартером вариант эффективнее и моего и floor()

Чуть лучше или по крайней мере не хуже должен быть вариант с использованием local floor=math.floor. Вызов же math.floor имеет двойную цену: за обращение к полю таблицы (глобальной переменной) и за, собственно, вызов функции. Что и видно по результатам теста. Локальный же вызов floor() работает шустро.

 

А учитывая, что вариант с использованием floor() выглядит наиболее очевидно, имеет смысл предпочесть именно его.

Изменено пользователем eu_tomat

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
4 часа назад, Zer0Galaxy сказал:

Опыт подтверждает твои выводы:

 

4 часа назад, eu_tomat сказал:

не хуже должен быть вариант с использованием local floor=math.floor

Чекнул дополнительно пару известных вариантов округления. Топикстартеру респект за наиболее производительное решение:

Constant        0.017
Upvalue         0.023
math.floor      0.027
floor (no indexing)     0.025
Lua 5.3+: (num + 0.5) // 1        0.022
Lua 5.2+: num - num % 1         0.026

 

  • Нравится 1
  • Спасибо 1
  • В шоке 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
2 часа назад, ECS сказал:

Чекнул дополнительно пару известных вариантов округления.

Что-то у тебя интервал времени получился крошечный. Там погрешность получается большая. Возьмём интервал побольше.

 

Код:

Скрытый текст

local uptime=os.clock

local function round1(num)
    return num + (2 ^ 52 + 2 ^ 51) - (2 ^ 52 + 2 ^ 51)
end

local huge = 2 ^ 52 + 2 ^ 51
local function round2(num)
    return num + huge - huge
end

n = 2e7

os.sleep(0.05)start=uptime()
for i=1,n do
  round1(1.234)
end
print("Constant ",uptime()-start)

os.sleep(0.05)start=uptime()
for i=1,n do
  round2(1.234)
end
print("Upvalue ",uptime()-start)

os.sleep(0.05)start=uptime()
for i=1,n do
  math.floor(1.234+0.5)
end
print("math.floor ",uptime()-start)

local floor=math.floor

os.sleep(0.05)start=uptime()
for i=1,n do
  floor(1.234+0.5)
end
print("local floor ",uptime()-start)

local function round3(num)
  return (num+0.5)//1
end

os.sleep(0.05)start=uptime()
for i=1,n do
  round3(1.234)
end
print("(num+0.5)//1 ",uptime()-start)

 

Результат:

Скрытый текст

NaIVxIx.png

Итог: лучшее время стабильно показывает local floor=math.floor

Версия мода OpenComputers-MC1.7.10-1.7.5.1290-universal.jar

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
6 минут назад, eu_tomat сказал:

Что-то у тебя интервал времени получился крошечный. Там погрешность получается большая

Интервал зависит от кол-ва итераций, а оно такое же, как в примере Zer0Galaxy. Тестил я на десктопном некомпилируемом Lua 5.3.1, лень кубач было ставить. Не нравится? Да пожалуйста, вон результат на 2e7 итераций:

Constant        1.152
Upvalue         1.375
math.floor      1.749
floor (no indexing)     1.425
Lua 5.3+: num + 0.5 // 1        1.524
Lua 5.2+: num - num % 1         1.733

И на опенкомпах:

 

image.png.8fe5e2f722501522215a38a8129d8854.png

 

Один фиг победа за первым методом

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 минуту назад, ECS сказал:

Один фиг победа за первым методом

Что-то не бьются у нас результаты. Какая у тебя версия OpenComputers?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 минуту назад, eu_tomat сказал:

Что-то не бьются у нас результаты. Какая у тебя версия OpenComputers?

OpenComputers-MC1.12.2-1.7.5.192.jar

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 час назад, eu_tomat сказал:

Что-то не бьются у нас результаты. Какая у тебя версия OpenComputers?

Как это влияет?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
3 минуты назад, NEO сказал:

Как это влияет?

Тогда что влияет? Какие предлагаешь варианты?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 час назад, eu_tomat сказал:

Тогда что влияет? Какие предлагаешь варианты?

Железо скорее. Луа-консоль запускал на рабочей вдске, сервак кубача поднимаю там же, т.к. сингловый клиент на дешманском ноуте умирает с TLWY даже на 1млн итераций, не говоря уже о 20 млн. С точки зрения дилетанта могу предположить, что наибольшее влияние на однопоточные вычисления оказывает набор инструкций ЦП, объем кеша и частота. Возможно, надо байт-код для каждого метода и каждой машины чекать, чтобы сказать наверняка (он вообще может отличаться для одинаковых версий луа?)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
11 час назад, ECS сказал:

Железо скорее. Луа-консоль запускал на рабочей вдске, сервак кубача поднимаю там же, т.к. сингловый клиент на дешманском ноуте умирает с TLWY даже на 1млн итераций, не говоря уже о 20 млн. С точки зрения дилетанта могу предположить, что наибольшее влияние на однопоточные вычисления оказывает набор инструкций ЦП, объем кеша и частота.

Я несколько лет пользовался другим объяснением, но с учётом новой информации его, возможно, придётся пересмотреть.

 

А объяснение было таким. На обычных операциях (если это не обработка длинных строк или преобразование больших таблиц) наибольший вклад в затраты времени даёт интерпретатор Lua. Вклад же полезной нагрузки минимален. Поэтому простая функция, написанная на Lua, будет исполняться дольше функции из стандартных библиотек. И мой опыт всегда подтверждал эту гипотезу.

 

Ситуация может резко измениться, если отказаться от оборачивания кода в функцию. Например, вынеся код return (num+0.5)//1 из функции можно получить примерно 5-кратное ускорение выполнения этого участка кода. И это тоже объяснимо. Обработка вызова функции, наверное, во всех языках программирования является затратной в сравнении с арифметическими операциями.

 

Кстати, @OpenReactor, обрати на это внимание. Наиболее быстрый способ округления на Lua не должен содержать вызова какой-либо функции.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
7 часов назад, eu_tomat сказал:

Я несколько лет пользовался другим объяснением, но с учётом новой информации его, возможно, придётся пересмотреть.

 

А объяснение было таким. На обычных операциях (если это не обработка длинных строк или преобразование больших таблиц) наибольший вклад в затраты времени даёт интерпретатор Lua. Вклад же полезной нагрузки минимален. Поэтому простая функция, написанная на Lua, будет исполняться дольше функции из стандартных библиотек. И мой опыт всегда подтверждал эту гипотезу.

 

Ситуация может резко измениться, если отказаться от оборачивания кода в функцию. Например, вынеся код return (num+0.5)//1 из функции можно получить примерно 5-кратное ускорение выполнения этого участка кода. И это тоже объяснимо. Обработка вызова функции, наверное, во всех языках программирования является затратной в сравнении с арифметическими операциями.

 

Кстати, @OpenReactor, обрати на это внимание. Наиболее быстрый способ округления на Lua не должен содержать вызова какой-либо функции.

Спасибо

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
7 часов назад, eu_tomat сказал:

А объяснение было таким. На обычных операциях (если это не обработка длинных строк или преобразование больших таблиц) наибольший вклад в затраты времени даёт интерпретатор Lua. Вклад же полезной нагрузки минимален. Поэтому простая функция, написанная на Lua, будет исполняться дольше функции из стандартных библиотек. И мой опыт всегда подтверждал эту гипотезу.

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

 

А как быть в нашем случае, когда эквивалентный код под одной VM на различном железе выдает различную производительность?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
14 минуты назад, ECS сказал:

А как быть в нашем случае, когда эквивалентный код под одной VM на различном железе выдает различную производительность?

Это-то я и пытаюсь понять. Выше я упомянул, что готов пересмотреть это объяснение. В этом контексте оно не является обоснованием верности одних или других результатов измерений. Это скорее объяснение того, почему я изначально усомнился в правильность твоих замеров, списав возникшее расхождение на обычную погрешность.

 

23 часа назад, ECS сказал:

OpenComputers-MC1.12.2-1.7.5.192.jar

Я перепроверил. На этой версии наши результаты также расходятся. Это стандартный пакет? Какой-либо модификации не подвергался? Если нет, то остаётся только влияние железа. Какой у тебя процессор?

 

Процессор, на котором проводил замеры я:

$ cat /proc/cpuinfo | grep name | uniq -c
      8 model name	: Intel(R) Core(TM) i7-4770K CPU @ 3.50GHz

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
2 часа назад, eu_tomat сказал:

Какой-либо модификации не подвергался?

Нет, офк. Я ж скинул аналогичный результат на чистом консольном луа той же версии, так чего на разность модов-то грешить? Загвоздка явно в поведении железяк. Но боюсь, я абсолютно некомпетентен в этом вопросе, чтобы сгенерировать какие-либо выводы. Цпуинфа:

8 model name      : Intel(R) Xeon(R) Silver 4214R CPU @ 2.40GHz

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в тему...

×   Вы вставили отформатированное содержимое.   Удалить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.


×
×
  • Создать...