PDA

Просмотр полной версии : [Function] GetTickDiff - исправление проблемы переполнения для GetTickCount



ziggi
02.08.2016, 02:46
Описание:

Функция для вычисления времени, прошедшего между двумя вызовами GetTickCount(), с учётом возможности переполнения переданных значений.

Параметры:

newtick - текущее значение времени
oldtick - предыдущее значение времени


Возвращаемое значение:

Функция возвращает время, прошедшее между двумя переданными в неё значениями.

Код:

stock GetTickDiff(newtick, oldtick)
{
return newtick - oldtick;
}

Примечания:
Всегда знал, что данный фикс уже существует и не испытывал надобности в его написании, но после изучения реализации, рекомендуемой в wiki (http://pastebin.com/BZyaJpzs), понял, что она работает не корректно. Создал Pull Request (https://github.com/Southclaw/ScavengeSurvive/pull/294) в репозитории автора этого фикса, в котором вы можете найти код теста и его результаты. Также актуальную версию функции можно найти на GitHubGist (https://gist.github.com/ziggi/5d7d8dc42f54531feba7ae924c608e73).

Пример использования:

static
LastShot[MAX_PLAYERS];

public OnPlayerWeaponShot(playerid, weaponid, hittype, hitid, Float:fX, Float:fY, Float:fZ)
{
new
current_tick = GetTickCount();
interval = GetTickDiff(current_tick, LastShot[playerid]);

printf("Last shot interval: %i ms", interval);

LastShot[playerid] = current_tick;
return 1;
}


Автор: ziggi

DCPSHER
18.06.2018, 03:09
Спасибо за фикс! Как раз изучал эту тему сейчас.

Можно, я думаю, добавить ссылку на гитхаб с ним(https://gist.github.com/ziggi/5d7d8dc42f54531feba7ae924c608e73) в тему, или исправить здесь код до актуального, т.к. я сначала увидел код по ссылке с Вики Самп, а затем в этой теме, и лишь ревизии гиста позволили мне понять, что там актуальный, а здесь нет.

ziggi
18.06.2018, 22:35
Спасибо за фикс! Как раз изучал эту тему сейчас.

Можно, я думаю, добавить ссылку на гитхаб с ним(https://gist.github.com/ziggi/5d7d8dc42f54531feba7ae924c608e73) в тему, или исправить здесь код до актуального, т.к. я сначала увидел код по ссылке с Вики Самп, а затем в этой теме, и лишь ревизии гиста позволили мне понять, что там актуальный, а здесь нет.

Спасибо, забыл про эту тему совсем. Заметил, что в функции есть лишнее условие - обновил функцию ещё раз.

Daniel_Cortez
19.06.2018, 15:32
(cellmax - oldtick + 1) - (cellmin - newtick)

Вот это довольно интересное выражение. А интересно оно тем, что cellmax + 1 из-за целочисленного переполнения даёт cellmin и выражение можно записать так:

(cellmin - oldtick) - (cellmin - newtick)

Раскрываем скобки:

cellmin - oldtick - cellmin + newtick

Упрощаем (cellmin и -cellmin взаимоуничтожаются):

newtick - oldtick

Но стоп, это ведь тот же самый код, что и вне ветки if !

stock GetTickDiff(newtick, oldtick)
{
if (oldtick > newtick) {
return newtick - oldtick;
}
return newtick - oldtick;
}

Я что-то делаю не так? Очень хотелось бы узнать, чем вся эта функция лучше, чем просто newtick - oldtick.


UPD: Написал на скорую руку тест, чтобы выявить разницу в результатах между функцией и newtick - oldtick.
В нём производится перебор всего диапазона возможных значений oldtick, при этом newtick на 10 больше oldtick в первом цикле и на 10 меньше во втором. Если результаты функции и простого вычитания отличаются, в консоль выводится сообщение.
Также добавил вывод номеров итераций, кратных 100_000_000, чтобы убедиться, что код выполняется.


#include <a_samp>

stock GetTickDiff(newtick, oldtick)
{
if (oldtick > newtick)
{
return (cellmax - oldtick + 1) - (cellmin - newtick);
}
return newtick - oldtick;
}

#define GetTickDiff_simplified(%0,%1) ((%0)-(%1))

main()
{
printf("testing...");
static newtick = 10, oldtick = 0;
static diff1, diff2;
do {
if (oldtick % 100_000_000 == 0)
printf("%d", oldtick);
diff1 = GetTickDiff(newtick, oldtick);
diff2 = GetTickDiff_simplified(newtick, oldtick);
if (diff1 != diff2)
printf("result for (%d, %d) differ: %d, %d", newtick, oldtick, diff1, diff2);
} while ((++newtick, ++oldtick) != 0);
newtick = -10; // oldtick is already 0
do {
if (oldtick % 100_000_000 == 0)
printf("%d", oldtick);
diff1 = GetTickDiff(newtick, oldtick);
diff2 = GetTickDiff_simplified(newtick, oldtick);
if (diff1 != diff2)
printf("result for (%d, %d) differ: %d, %d", newtick, oldtick, diff1, diff2);
} while ((++newtick, ++oldtick) != 0);
printf("done");
}


Вывод:


testing...
0
100000000
200000000
300000000
400000000
500000000
600000000
700000000
800000000
900000000
1000000000
1100000000
1200000000
1300000000
1400000000
1500000000
1600000000
1700000000
1800000000
1900000000
2000000000
2100000000
-2100000000
-2000000000
-1900000000
-1800000000
-1700000000
-1600000000
-1500000000
-1400000000
-1300000000
-1200000000
-1100000000
-1000000000
-900000000
-800000000
-700000000
-600000000
-500000000
-400000000
-300000000
-200000000
-100000000
0
100000000
200000000
300000000
400000000
500000000
600000000
700000000
800000000
900000000
1000000000
1100000000
1200000000
1300000000
1400000000
1500000000
1600000000
1700000000
1800000000
1900000000
2000000000
2100000000
-2100000000
-2000000000
-1900000000
-1800000000
-1700000000
-1600000000
-1500000000
-1400000000
-1300000000
-1200000000
-1100000000
-1000000000
-900000000
-800000000
-700000000
-600000000
-500000000
-400000000
-300000000
-200000000
-100000000
done

Как видно, результаты идентичны, ни одного сообщения об отличии.

ziggi
20.06.2018, 18:01
Да уж, забавно)) Обновил.