XGM Forum
Сайт - Статьи - Проекты - Ресурсы - Блоги

Форуме в режиме ТОЛЬКО ЧТЕНИЕ. Вы можете задать вопросы в Q/A на сайте, либо создать свой проект или ресурс.
Вернуться   XGM Forum > Warcraft> Академия: форум для вопросов> Jass
Ник
Пароль
Войти через VK в один клик
Сайт использует только имя.

Результаты опроса: Оптимизируем ли код?
Да 19 63.33%
Нет 11 36.67%
Голосовавшие: 30. Вы еще не голосовали в этом опросе

Закрытая тема
 
nic666

offline
Опыт: 5,612
Активность:
DioD
просто "оптимизировать алгоритм" такого понятия нет. Можно оптимизировать алгоритм ПО КРИТЕРИЮ. Известные критерии: скорость выполнения, экономия памяти, компактность кода.

Я и спрашивал о КРИТЕРИИ!

Вы конечно могли иметь ввиду ВООБЩЕМ, то есть как лучше. Но лучше - это понятие относительное. Например, есть фанаты скорости, а есть фанаты компактности кода. Для каждого из них лучшее - это своЁ!

Как вы оцениваете что лучше? Если вы сравниваете объем результата в байтах, то вы по компактности, если засекаете время работы - то по скорости.

Что касается УТЕЧЕК:
- это конкретно ошибки в реализации джаса или пользовательского кода. Исправление ошибок к оптимизации отношения не имеет, это качественно иной процесс.

Сейчас я вам выложу пару решений по предыдущему примеру, которые по-своему хороши.
Старый 11.01.2007, 10:54
DioD

offline
Опыт: 45,134
Активность:
красивый код != правильный
о оптимизации кода по его длине речи быть не может
код что вызывает засорение памяти уже неоптимален, так как некорректно использует память.
Старый 11.01.2007, 10:58
nic666

offline
Опыт: 5,612
Активность:
утечка=ошибка
ошибка=нет кода
нет кода=оптимизировать нечего

Две разные вещи:
1) Исправление ошибок
2) оптимизация

Код:
function I2Z takes integer i returns string
 if (i>9) then 
   return "0"+I2S(i)
 else 
   return I2S(i)
 endif
endfunction

function GetMyTime takes nothing returns string
set udg_TimeStamp = ( udg_TimeStamp + 1 )
return I2Z(udg_TimeStamp/3600)+":" +I2Z(ModuloInteger(udg_TimeStamp/60,60))+":"+I2Z(ModuloInteger(udg_TimeStamp,60))
endfunction

Вот вам код function GetMyTime... он ПО-СВОЕМУ оптимален.
А в кэш надо писать udg_TimeStamp и не каждую секунду, а только когда надо

nic666 добавил:
Это был пример комактности, сейчас могу сделать пример оптимизации скорости.

Только крутится два варианта кода незнаю какой выбрать
1) объем около 30 кб
2) объем около 690кб

Вам какой сделать?
тот что быстрее?
Старый 11.01.2007, 11:10
DioD

offline
Опыт: 45,134
Активность:
давай все, потом оценим
Старый 11.01.2007, 11:18
nic666

offline
Опыт: 5,612
Активность:
Еще вопрос:
зачем читать из кеша значение TimeStamp каждую секунду?
Ведь гораздо эффективнее хранить копию этой величины в глобальной переменной.
Щас сделаю пример на 30Кб, а на 690Кб это по-моему уже безумно тратить на одну функцию столько объема...
а безумие это иное качественное состояние и к оптимизации мало подходит.
Щас выложу минут через 20...
Старый 11.01.2007, 11:22
DioD

offline
Опыт: 45,134
Активность:
если функция считает время в секундах, надо учесть поведение при запусках 100 раз в секунду и если запускает раз в час тоже
Старый 11.01.2007, 11:34
nic666

offline
Опыт: 5,612
Активность:
Цитата:
если функция считает время в секундах, надо учесть поведение при запусках 100 раз в секунду и если запускает раз в час тоже

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


Вот вам tot пример GetMyTime? но вообще-то карта с ним почему-то стала весить 80кб, когда тестировал...
Код:
function InitMyTime takes nothing returns nothing
//-------Next integer init

set udg_N[0] = 1
...............................................
...............................................
..............................................
set udg_N[3595] = 3596
set udg_N[3596] = 3597
set udg_N[3597] = 3598
set udg_N[3598] = 3599
set udg_N[3599] = 0

//-------The special mark
set udg_N[3600] = 1

//-------string MinSec init 00:00 - 59:59
set udg_ToS[0] = "00:00"
set udg_ToS[1] = "00:01"
........................................................
........................................................
........................................................
set udg_ToS[3597] = "59:57"
set udg_ToS[3598] = "59:58"
set udg_ToS[3599] = "59:59"

//-------string Hours init 00-23
set udg_ToS[3600] = "00:"
set udg_ToS[3601] = "01:"
set udg_ToS[3602] = "02:"
.......................................
......................................
......................................
set udg_ToS[3622] = "22:"
set udg_ToS[3623] = "23:"
endfunction

function GetMyTime takes nothing returns string
 set udg_MinSec=udg_N[udg_MinSec]
 set udg_Hour=udg_Hour + udg_N[3600 + udg_MinSec]
 return udg_ToS[3600 + udg_Hour] + udg_ToS[udg_MinSec]
endfunction


Как видите в самой функции нет ничего кроме сложений и обращения к массивам! Обращение к массивам это по сути сложение и умножение на 4. Но все равно это быстрее, чем все что здесь опубликовано выше...

Чуть не забыл глобалки
Hour, MinSec - целые
N - массив целых
ToS - массив строк

Прилагаю полный код атачем, так не влазит.......
Прикрепленные файлы
Тип файла: rar GetMyTimeCode.rar (2.9 Кбайт, 16 просмотров )
Старый 11.01.2007, 12:16
adic3x

offline
Опыт: 108,439
Активность:
nic666, а почему ты присваиваешь не через loop?
Старый 11.01.2007, 12:22
nic666

offline
Опыт: 5,612
Активность:
а так быстрее ;)
Старый 11.01.2007, 12:25
adic3x

offline
Опыт: 108,439
Активность:
nic666, а размер кода? Оно то может и быстрее, но я бы изпользовал циклы)
Старый 11.01.2007, 12:28
DioD

offline
Опыт: 45,134
Активность:
спайка строк бред, надо было так делать
S[0] = " <00:00:00> "
S[1] = " <00:00:01> "
/
S[3599] = " <00:59:59> "
Старый 11.01.2007, 12:46
nic666

offline
Опыт: 5,612
Активность:
ADOLF так читай выше...я тут и тру о том, что задача неточно поставлена. Увеличение объема при оптимизации скорости - это очень частое явление.



А вот промежуточный вариант карта с ним весит всего 18кб, но он чуть медленее предыдущего...

Код:
function InitMyTime takes nothing returns nothing
//-------Next integer init

set udg_N[0] = 1
set udg_N[1] = 2
set udg_N[2] = 3
set udg_N[3] = 4
set udg_N[4] = 5
set udg_N[5] = 6
set udg_N[6] = 7
set udg_N[7] = 8
set udg_N[8] = 9
set udg_N[9] = 10
set udg_N[10] = 11
set udg_N[11] = 12
set udg_N[12] = 13
set udg_N[13] = 14
set udg_N[14] = 15
set udg_N[15] = 16
set udg_N[16] = 17
set udg_N[17] = 18
set udg_N[18] = 19
set udg_N[19] = 20
set udg_N[20] = 21
set udg_N[21] = 22
set udg_N[22] = 23
set udg_N[23] = 24
set udg_N[24] = 25
set udg_N[25] = 26
set udg_N[26] = 27
set udg_N[27] = 28
set udg_N[28] = 29
set udg_N[29] = 30
set udg_N[30] = 31
set udg_N[31] = 32
set udg_N[32] = 33
set udg_N[33] = 34
set udg_N[34] = 35
set udg_N[35] = 36
set udg_N[36] = 37
set udg_N[37] = 38
set udg_N[38] = 39
set udg_N[39] = 40
set udg_N[40] = 41
set udg_N[41] = 42
set udg_N[42] = 43
set udg_N[43] = 44
set udg_N[44] = 45
set udg_N[45] = 46
set udg_N[46] = 47
set udg_N[47] = 48
set udg_N[48] = 49
set udg_N[49] = 50
set udg_N[50] = 51
set udg_N[51] = 52
set udg_N[52] = 53
set udg_N[53] = 54
set udg_N[54] = 55
set udg_N[55] = 56
set udg_N[56] = 57
set udg_N[57] = 58
set udg_N[58] = 59
set udg_N[59] = 0


//-------The special mark
set udg_N[60] = 1

//-------string MinSec init 00:00 - 59:59
set udg_ToS[0] = "00"
set udg_ToS[1] = "01"
set udg_ToS[2] = "02"
set udg_ToS[3] = "03"
set udg_ToS[4] = "04"
set udg_ToS[5] = "05"
set udg_ToS[6] = "06"
set udg_ToS[7] = "07"
set udg_ToS[8] = "08"
set udg_ToS[9] = "09"
set udg_ToS[10] = "10"
set udg_ToS[11] = "11"
set udg_ToS[12] = "12"
set udg_ToS[13] = "13"
set udg_ToS[14] = "14"
set udg_ToS[15] = "15"
set udg_ToS[16] = "16"
set udg_ToS[17] = "17"
set udg_ToS[18] = "18"
set udg_ToS[19] = "19"
set udg_ToS[20] = "20"
set udg_ToS[21] = "21"
set udg_ToS[22] = "22"
set udg_ToS[23] = "23"
set udg_ToS[24] = "24"
set udg_ToS[25] = "25"
set udg_ToS[26] = "26"
set udg_ToS[27] = "27"
set udg_ToS[28] = "28"
set udg_ToS[29] = "29"
set udg_ToS[30] = "30"
set udg_ToS[31] = "31"
set udg_ToS[32] = "32"
set udg_ToS[33] = "33"
set udg_ToS[34] = "34"
set udg_ToS[35] = "35"
set udg_ToS[36] = "36"
set udg_ToS[37] = "37"
set udg_ToS[38] = "38"
set udg_ToS[39] = "39"
set udg_ToS[40] = "40"
set udg_ToS[41] = "41"
set udg_ToS[42] = "42"
set udg_ToS[43] = "43"
set udg_ToS[44] = "44"
set udg_ToS[45] = "45"
set udg_ToS[46] = "46"
set udg_ToS[47] = "47"
set udg_ToS[48] = "48"
set udg_ToS[49] = "49"
set udg_ToS[50] = "50"
set udg_ToS[51] = "51"
set udg_ToS[52] = "52"
set udg_ToS[53] = "53"
set udg_ToS[54] = "54"
set udg_ToS[55] = "55"
set udg_ToS[56] = "56"
set udg_ToS[57] = "57"
set udg_ToS[58] = "58"
set udg_ToS[59] = "59"
set udg_ToS[60] = "00"
endfunction

function GetMyTime takes nothing returns string
 set udg_Sec=udg_N[udg_Sec]

 set udg_Min=udg_Min + udg_N[60 + udg_Sec]

 set udg_Hour=udg_Hour + udg_N[ 120 - udg_Min]

 set udg_Min=udg_N[udg_Min-1]

 return udg_ToS[udg_Hour]+":"+udg_ToS[udg_Min]+":"+udg_ToS[udg_Sec]
endfunction


Переменные
udg_Hour , udg_Min, udg_Sec целые
udg_N массив целых
udg_ToS массив строк

Я бы этот все таки предпочел предыдущему...

nic666 добавил:
Цитата:
Сообщение от DioD
спайка строк бред, надо было так делать

S[0] = " <00:00:00> "
S[1] = " <00:00:01> "
/////
S[3599] = " <00:59:59> "


Если это бред и часов всегда НОЛЬ, то зачем тебе переменная Hour вообще? Тогда ее можно выкинуть.

Именно вариант с 8 значными строками от 00:00:00 до 23:59:59 я и хотел предложить, по моим подсчетам он бы весил 690кб. А ограничение массива на 8191 элемент можно обойти, используя несколько массивов, или выделяя части из одной строки.

nic666 добавил:
Нет пожалуй на 690кб вариант быстрее не будет, там на обход ограничения 8192 портебуется дополнительный код...

nic666 добавил:
Ну вот последний вариант по пожелпниям ADOLF через loop то есть компактный
и такой же быстрый

Код:
function InitMyTime takes nothing returns nothing
local integer i
local integer j
local integer t
//-------Next integer init
    set i = 0
    loop
        exitwhen i > 3558
        set udg_N[i] = i + 1 
        set i = i + 1
    endloop

set udg_N[3599] = 0

//-------The special mark
set udg_N[3600] = 1

//-------string Hours init 00-23

set udg_ToS[3600] = "00"
set udg_ToS[3601] = "01"
set udg_ToS[3602] = "02"
set udg_ToS[3603] = "03"
set udg_ToS[3604] = "04"
set udg_ToS[3605] = "05"
set udg_ToS[3606] = "06"
set udg_ToS[3607] = "07"
set udg_ToS[3608] = "08"
set udg_ToS[3609] = "09"

//-------string MinSec init 00:00 - 59:59

set udg_ToS[0] = "00"
set udg_ToS[1] = "01"
set udg_ToS[2] = "02"
set udg_ToS[3] = "03"
set udg_ToS[4] = "04"
set udg_ToS[5] = "05"
set udg_ToS[6] = "06"
set udg_ToS[7] = "07"
set udg_ToS[8] = "08"
set udg_ToS[9] = "09"

    set i = 10
    loop
        exitwhen i > 59
        set udg_ToS[i] = I2S(i)
        set udg_ToS[3600+i] = set udg_ToS[i]
        set i = i + 1
    endloop

   set t = 3599

    set i = 59
    loop
        set j = 59
         loop
           set udg_ToS[t] = ":"+udg_ToS[i]+":"+udg_ToS[j]
          
           set j = j - 1
           set t = t - 1
           exitwhen j == -1
        endloop
        set i = i - 1
       exitwhen i == -1
    endloop

endfunction


function GetMyTime takes nothing returns string
 set udg_MinSec=udg_N[udg_MinSec]
 set udg_Hour=udg_Hour + udg_N[3600 + udg_MinSec]
 return udg_ToS[3600 + udg_Hour] + udg_ToS[udg_MinSec]
endfunction

Отредактировано nic666, 11.01.2007 в 16:22.
Старый 11.01.2007, 14:05
herr_horror
Фиолетовый андроид
offline
Опыт: 139
Активность:
Нашел неплохой вариант. Что-то навеяло из курса дискретной математики...
Код:
local integer T[0] = CFG_I("Seconds") 
    local integer T[1] = CFG_I("Minutes")
    local integer T[2] = CFG_I("Hours"  )
    local integer p = 1 
    // Это признак переноса из предыдущего в следующий разряд  
    // Мы сразу делаем равным единице. чтобы Seconds=Seconds + p 
    local integer i=0 

    local string Time = "> "

    // Обратите внимание! В исходном примере содержится ошибка! Нет роверки на то, 
    // что часы будут больше 24! Поэтому этот код является оптимизированной   
    // версией исходного, причем с такой же ошибкой!

   loop
        exitwhen i > 2

        set T[i] = T[i] + p  // Учитываем перенос из предыдущего разряда
        set p = IMaxBJ (T[i]-59, 0) 
        // Новое значение переноса
        // если я правильно понял АПИ - IMaXBJ  - вернет максимум          
        // между T[i]-59 и 0

        set T[i] = T[i]*(1-p) 
        // если принак переноса взвелся -обнуляем текущий разряд

 
        if T[i]<10 then Time = ":0" + I2S(T[i]) + Time
        else    Time = ":" + I2S(T[i]) + Time
        endif

         set i = i + 1
    endloop

      
    set Time = " <"+ SubString(Time, 1, 11) 
    // Это расплата за то, что у нас в цикле лишнее
    // ведущее двоеточие перед числом
                                                              
   
    call I_CFG("Seconds", T[0] )
    call I_CFG("Minutes", T[1] )
    call I_CFG("Hours"  , T[2]   )

    call StoreString(ИГРОВАЯ_КОНСТАНТА,"CFG","Time",Time)

    set  T = null // Массив обнулять легко!
    set  i = null
    set  p = null
    set  Time = null
endfunction

Отредактировано herr_horror, 11.01.2007 в 15:15.
Старый 11.01.2007, 15:09
J
expert
offline
Опыт: 48,447
Активность:
Цитата:
Сообщение от herr_horror
Код:
local integer T[0] = CFG_I("Seconds") 
    local integer T[1] = CFG_I("Minutes")
    local integer T[2] = CFG_I("Hours"  )
    ...
    set  T = null // Массив обнулять легко!

no comment


Jon добавил:
Цитата:
Сообщение от Заголовок темы
Задача №-1

№-1? будут другие? когда?
Старый 11.01.2007, 16:07
nic666

offline
Опыт: 5,612
Активность:
Ай яй яй... исправил в своем последнем варианте
Код:
set i = 10
    loop
        exitwhen i > 59
        set udg_ToS[i] = I2S(i)
        set udg_ToS[3600+i] = set udg_ToS[i]
        set i = i + 1
    endloop


а было
Код:
set i = 10
    loop
        exitwhen i > 59
        set udg_ToS[i] = I2S(i)
        set udg_ToS[3600+i] = I2S(i)
        set i = i + 1
    endloop


Вообщем именно свой последний вариант я и считаю самым лучшим.
Старый 11.01.2007, 16:25
herr_horror
Фиолетовый андроид
offline
Опыт: 139
Активность:
Цитата:
Сообщение от Jon
no comment

Я более у2.718281828459045бищного синтаксиса в жизни не видел! Я вообще уже сомневаюсь, что джасс - Тьюринг-полный язык. Еле удержался, чтобы не написать нормальным языком. Не знаю, как создается локальный массив! Не знаю! Тут я не нашел.
Предположил, что так. Поправь, я тебе спасибо скажу.
Старый 11.01.2007, 16:39
J
expert
offline
Опыт: 48,447
Активность:
Цитата:
Не знаю, как создается локальный массив! Не знаю!

local <тип> array <название>
обнулять сразу весь цыкл нельзя.. только по элементам
(целочисленый масив обнулять null-ом тоже не рекомендую)
Старый 11.01.2007, 16:51
herr_horror
Фиолетовый андроид
offline
Опыт: 139
Активность:
Цитата:
Сообщение от Jon
local <тип> array <название>
обнулять сразу весь цыкл нельзя.. только по элементам
(целочисленый масив обнулять null-ом тоже не рекомендую)


Понял спасибо, буду знать. Так стоп! А почему обнулять локальные .. вообще надо?
Они же локальные! Они живы только внутри двух операторных скобок : начало функции - конец_функции.
Любая переменная, объявленная как локал - должна быть в стеке, стало быть по рету эта память будет недоступна. Даже если близардовцы сделали велосипед с квадратными колесами, тут должно быть что-то вроде GarbageCollection? Я например был приятно удивлен, когда нашел что можно на джазе создавать потоки, они что ли вообще не чистятся никак?
Да.. и массив это же только указатель на первый элемент. Его грохнуть ВСЕГДА было проще папиной репы. Джаз меня удивляет!


Ладно. кончаю оффтоп. В общем АЛГОРИТМИЧЕСКИ ДАННЫЙ ПРИМЕР можно оптимизировать так:

Код:
loop
        exitwhen i > 2
        set T[i] = T[i] + p  // Учитываем перенос из предыдущего разряда
        set p = IMaxBJ (T[i]-59, 0) 
        set T[i] = T[i]*(1-p) 
        if T[i]<10 then Time = ":0" + I2S(T[i]) + Time
        else    Time = ":" + I2S(T[i]) + Time
        endif
         set i = i + 1
    endloop


Пойду жрать.
Старый 11.01.2007, 17:00
DioD

offline
Опыт: 45,134
Активность:
тем кто пошел кушать - бон аппетит, остальные думайте, я пока подготовлю то что вроде как я хотел вам поведать как первую стадию оптимизации.

ПС больше 24 часов не бывает, так что если пройдёт 3600*24 секунд надо будет сбросить их до нуля, что не сложно.

Код:
local integer T[0] = CFG_I("Seconds") 
    local integer T[1] = CFG_I("Minutes")
    local integer T[2] = CFG_I("Hours"  )


Взял то что было ближе

1) Секунды меняются раз в секунду, поэтому считывать каждую секунду часы и минуты нецелесообразно.
Первая стадия это именно чтение по необходимости, а не постоянно.
Так же как и записать

Читать если требуется и записывать так же

Надеюсь это понятно?
Старый 12.01.2007, 02:47
nic666

offline
Опыт: 5,612
Активность:
DioD
Я давно тебе говорил, что в периодическом триггере не должно быть никаких чтений из кеша ВООБЩЕ! Надо копии хранить в глобалках и их модифицировать. На крайний случай можно записывать в кеш, но и это не стоит делать раз в секунду. Лучше сделать еще один триггер и сохранять все что надо 1 раз в минуту, или 5 минут.

nic666 добавил:
P.S.
Если кто не знает, то кеш придуман близардом для компаний, чтобы переносить элементы между миссиями. Изначально никаких гарантий его скоростной работы небыло. И он и работает в 10-100 раз медленее чем массивы и глобалки... скорость работы зависит от заполненности
Старый 12.01.2007, 10:44
Закрытая тема

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы можете скачивать файлы

BB-коды Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход



Часовой пояс GMT +3, время: 18:46.