реклама на сайте
подробности

 
 
> Программный таймер, как красиво обойти переполнение?
Леонид Иванович
сообщение Jan 24 2014, 09:53
Сообщение #1


Местный
***

Группа: Участник
Сообщений: 318
Регистрация: 21-07-06
Из: Минск
Пользователь №: 18 986



Есть прерывание с периодом 1 мс, где инкрементируется 32-разрядный счетчик:

Код
void SysTick_Handler(void)
{
  TSysTimer::Counter++;
}


При необходимости формирования интервала программа может запустить один из программных счетчиков:

Код
void TSoftTimer::Start(uint32_t t)
{
  FinalCount = TSysTimer::Counter + t;
}


Истек ли интервал, проверяется так:

Код
bool TSoftTimer::Over(void)
{
  return(TSysTimer::Counter >= FinalCount);
}


Всё хорошо, но примерно через 50 дней счетчик TSysTimer::Counter переполнится и всё сломается. Как красиво это обойти? При этом можно наложить ограничение, что формируемый интервал никогда не превышает половины (или даже четверти) периода счетчика, а проверка переполнения тоже делается часто, много раз за период счетчика.


--------------------
Go to the top of the page
 
+Quote Post
4 страниц V   1 2 3 > »   
Start new topic
Ответов (1 - 52)
ViKo
сообщение Jan 24 2014, 10:21
Сообщение #2


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Нужно не сравнивать числа, а вычитать. Тогда отрицательная разность из-за ограничения разрядности превратится в положительную.
Go to the top of the page
 
+Quote Post
scifi
сообщение Jan 24 2014, 10:49
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(ViKo @ Jan 24 2014, 14:21) *
Нужно не сравнивать числа, а вычитать. Тогда отрицательная разность из-за ограничения разрядности превратится в положительную.

+1. Кстати, стандарт Си гарантирует, что при вычитании (unsigned int) - (unsigned int) результат будет корректным, пока разница во времени не превышает те самые 50 дней (для 32 бит), несмотря на переполнение первой или второй переменной.
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Jan 24 2014, 11:16
Сообщение #4


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(ViKo @ Jan 24 2014, 14:21) *
+1 Всегда так делаю.


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
RabidRabbit
сообщение Jan 24 2014, 11:21
Сообщение #5


Местный
***

Группа: Свой
Сообщений: 397
Регистрация: 3-12-09
Из: Россия, Москва
Пользователь №: 54 040



не знаю, как на ARM, а для x64 вычитание не прокатывает (gcc 4.7.2):
CODE
int gggg( uint32_t a1, uint32_t a2 )
{
40076c: 55 push %rbp
40076d: 48 89 e5 mov %rsp,%rbp
400770: 89 7d fc mov %edi,-0x4(%rbp)
400773: 89 75 f8 mov %esi,-0x8(%rbp)
return (a2 - a1) <= 0;
400776: 8b 45 f8 mov -0x8(%rbp),%eax
400779: 3b 45 fc cmp -0x4(%rbp),%eax
40077c: 0f 94 c0 sete %al
40077f: 0f b6 c0 movzbl %al,%eax
}
400782: 5d pop %rbp
400783: c3 retq

Go to the top of the page
 
+Quote Post
scifi
сообщение Jan 24 2014, 12:17
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(RabidRabbit @ Jan 24 2014, 15:21) *
не знаю, как на ARM, а для x64 вычитание не прокатывает (gcc 4.7.2):

Вы невнимательно читали. Типы должны быть unsigned int.
А в вашем примере перед вычитанием значения приводятся к типу int (он же int64_t) со всеми вытекающими...
Go to the top of the page
 
+Quote Post
Леонид Иванович
сообщение Jan 24 2014, 12:24
Сообщение #7


Местный
***

Группа: Участник
Сообщений: 318
Регистрация: 21-07-06
Из: Минск
Пользователь №: 18 986



О, спасибо, точно! А я было зациклился на сравнениях и чуть не погряз в условиях.

Код
TSoftTimer::TSoftTimer(uint32_t t = 0)
{
  Interval = t;
}

void TSoftTimer::Start(uint32_t t)
{
  Interval = t;
  StartCount = TSysTimer::Counter;
}

void TSoftTimer::Start()
{
  StartCount = TSysTimer::Counter;
}

void TSoftTimer::SetInterval(uint32_t t)
{
  Interval = t;
}

bool TSoftTimer::Over(void)
{
  return(TSysTimer::Counter - StartCount >= Interval);
}


--------------------
Go to the top of the page
 
+Quote Post
Tarbal
сообщение Jan 24 2014, 12:59
Сообщение #8


Профессионал
*****

Группа: Свой
Сообщений: 1 351
Регистрация: 21-05-10
Пользователь №: 57 439



Цитата(ViKo @ Jan 24 2014, 13:21) *
Нужно не сравнивать числа, а вычитать. Тогда отрицательная разность из-за ограничения разрядности превратится в положительную.


Важное замечание:
Вычитать нужно беззнаковые величины иначе результат будет неверный.


О! scifi уже написал sm.gif

Сообщение отредактировал Tarbal - Jan 24 2014, 12:59
Go to the top of the page
 
+Quote Post
Genadi Zawidowsk...
сообщение Jan 24 2014, 13:21
Сообщение #9


Профессионал
*****

Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634



а в NT x86 таймер 64 бита... и процедура получения значения для сравнения не используется ничего похожего на запрещение прерываний. Вам такое ней подойдёт? кроме того, можно ещё получить точный часов с "некруглой" частотой прерываний.
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Jan 24 2014, 13:49
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



А я вечно горожу проверку что типа если текущее меньше начального, то сложить хвост и начала... вот я балдаsm.gif)))

хотя последний раз я дошел до того что просто в таймере сделал
if(Delay >0)
Delay --;

и если надо выждать 10 тиков, то
Delay = 10; и проверяю что он не 0....

у вас все равно переменная Start задействована, так чего ей значение хранить, когда она может просто считаться назад?
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jan 24 2014, 14:03
Сообщение #11


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(Tarbal @ Jan 24 2014, 15:59) *
Важное замечание:
Вычитать нужно беззнаковые величины иначе результат будет неверный.

Возможно, и для знаковых будет все нормально.
Go to the top of the page
 
+Quote Post
scifi
сообщение Jan 24 2014, 14:28
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(ViKo @ Jan 24 2014, 18:03) *
Возможно, и для знаковых будет все нормально.

Да, возможно. Но это может зависеть от процессора и/или компилятора. А для типа unsigned int это гарантируется стандартом языка Си.
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Jan 24 2014, 16:50
Сообщение #13


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



для без знакового все просто, пусть 8 бит

250 - старт

0 - 250 == -250 = 0x06 (остальные биты улетают из за переполнения) == 6.
то есть 0 - 250 == 256 - 250 = 6

а если знаковое, то переполнение на 127.
и после 127 идет -128
120 - старт
-128 - 120 == -248 == 8 как должно было бы быть.

Все по битам верно, думаете компилятор может вмешаться?
Go to the top of the page
 
+Quote Post
mantech
сообщение Jan 24 2014, 17:50
Сообщение #14


Гуру
******

Группа: Участник
Сообщений: 2 219
Регистрация: 16-08-12
Из: Киров
Пользователь №: 73 143



Цитата(Genadi Zawidowski @ Jan 24 2014, 17:21) *
а в NT x86 таймер 64 бита... и процедура получения значения для сравнения не используется


Дак 64 бита никогда не переполнятся за всю жизнь biggrin.gif
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Jan 24 2014, 18:48
Сообщение #15


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



Цитата(mantech @ Jan 24 2014, 21:50) *
Дак 64 бита никогда не переполнятся за всю жизнь biggrin.gif

да ну бросьте.
это всего навсего
584 942.41735507203247082699137494 года
ничто по сравнению с жизнью вселенной...

если тик микросекунда..., а если пико?
Go to the top of the page
 
+Quote Post
Genadi Zawidowsk...
сообщение Jan 24 2014, 21:28
Сообщение #16


Профессионал
*****

Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634



Цитата(Golikov A. @ Jan 24 2014, 22:48) *
да ну бросьте.
это всего навсего
584 942.41735507203247082699137494 года
ничто по сравнению с жизнью вселенной...

если тик микросекунда..., а если пико?


НА примере XP дискретность 100 наносекунд. Инкрементируется на время периода системного тика.
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Jan 25 2014, 05:48
Сообщение #17


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



если 100 нан, то переполнение через 58.5 тыс лет.

Лично я рассчитываю что мои устройства спокойно преодолеют этот рубеж)
Go to the top of the page
 
+Quote Post
RabidRabbit
сообщение Jan 25 2014, 07:20
Сообщение #18


Местный
***

Группа: Свой
Сообщений: 397
Регистрация: 3-12-09
Из: Россия, Москва
Пользователь №: 54 040



Цитата(scifi @ Jan 24 2014, 16:17) *
Вы невнимательно читали. Типы должны быть unsigned int.
А в вашем примере перед вычитанием значения приводятся к типу int (он же int64_t) со всеми вытекающими...

Во-первых, покажите в моём примере, где "значения приводятся к типу int (он же int64_t)" sm.gif
Во-вторых, смотрите на вариант с unsigned int (правда, уже gcc 4.8.1), на всякий случай - 64-битные регистры те, что на букву r:
CODE
int gggg( unsigned int a1, unsigned int a2 )
{
40057d: 55 push %rbp
40057e: 48 89 e5 mov %rsp,%rbp
400581: 89 7d fc mov %edi,-0x4(%rbp)
400584: 89 75 f8 mov %esi,-0x8(%rbp)
//
return (a2 - a1) <= 0;
400587: 8b 45 f8 mov -0x8(%rbp),%eax
40058a: 3b 45 fc cmp -0x4(%rbp),%eax
40058d: 0f 94 c0 sete %al
400590: 0f b6 c0 movzbl %al,%eax
}
400593: 5d pop %rbp
400594: c3 retq

но конечно, это кривой пример, так как разность двух беззнаковых больше 0 и компилятор прав, что использует здесь проверку на равенство.
а вот при сравнении беззнакового числа с результатом вычитания двух беззнаковых чисел (как в итоге сделал ТС) компилятор использует кондишн "больше или равно" в беззнаковом варианте и всё работает sm.gif
Go to the top of the page
 
+Quote Post
scifi
сообщение Jan 25 2014, 07:58
Сообщение #19


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(RabidRabbit @ Jan 25 2014, 11:20) *
Во-первых, покажите в моём примере, где "значения приводятся к типу int (он же int64_t)" sm.gif

Чего там показывать? Это неявное приведение. Почитайте какую-нибудь книжку про язык Си. Ищите "integer promotion".
Go to the top of the page
 
+Quote Post
Ruslan-maniak
сообщение Oct 28 2014, 08:30
Сообщение #20


Частый гость
**

Группа: Участник
Сообщений: 92
Регистрация: 27-12-12
Из: Томск
Пользователь №: 74 999



НО в данном способе (с вычитанием) мы должны гарантировать это вычитание каждую миллисекунду. А иначе есть шанс прошляпить равенство таймера и счётчика и тогда всё посыпется. Ведь так?
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 28 2014, 08:54
Сообщение #21


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(Ruslan-maniak @ Oct 28 2014, 10:30) *
А иначе есть шанс прошляпить равенство таймера и счётчика и тогда всё посыпется. Ведь так?
Надо проверять не равенство, "а больше или равно" или "меньше или равно" - что подходит по контексту.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Ruslan-maniak
сообщение Oct 28 2014, 09:50
Сообщение #22


Частый гость
**

Группа: Участник
Сообщений: 92
Регистрация: 27-12-12
Из: Томск
Пользователь №: 74 999



В этом и заключается мой вопрос. В приведённом примере вычитания - нет сравнения. Там только вычитание. И срабатывает оно только тогда когда именно равенство между счётчиком и таймером. А если использовать сравнение, то опять же упираемся в переполнение счётчика. Так как красиво то сделать?

Сообщение отредактировал Ruslan-maniak - Oct 28 2014, 10:22
Go to the top of the page
 
+Quote Post
ViKo
сообщение Oct 28 2014, 10:27
Сообщение #23


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(Ruslan-maniak @ Oct 28 2014, 12:50) *
В этом и заключается мой вопрос. В приведённом примере вычитания - нет сравнения. Там только вычитание.

Есть. Нужно разницу сравнить с нулем (не на равенство...).
Go to the top of the page
 
+Quote Post
Ruslan-maniak
сообщение Oct 28 2014, 10:46
Сообщение #24


Частый гость
**

Группа: Участник
Сообщений: 92
Регистрация: 27-12-12
Из: Томск
Пользователь №: 74 999



На практике получается что если от меньшего беззнакового отнять большее беззнаковое то результат получается больше нуля, что собственно не удивительно. И данная конструкция не работает. Конечно если гарантировать программе что проверку она будет совершать точно каждую миллисекунду, то всё будет нормально. Но я бы не стал оставлять это на авось. На данный момент пришёл к такому решению: приводить разность перед сравнением к знаковому типу. И тогда всё нормально - обмануть таймер не получается какие бы значения счётчика не брать за начальные. Что об этом думаете?
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Oct 28 2014, 10:52
Сообщение #25


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



вы про какой из примеров то?

return(TSysTimer::Counter - StartCount >= Interval); - возвращается не разница, а результат сравнения.

У вас есть время начала и текущее время, их разность всегда есть интервал прошедшего времени. Проблемы только рассчитать интервал больше либо равный максимальному значению счетчика, потому что в этом случае после Максимум - 1, будет следовать 0, из-за переполнения. Но с этим ничего не сделаешь, кроме моего варианта
в прерывании таймера считать назад...

Цитата
Что об этом думаете?

думаем что вы не правыsm.gif

допустим у нас беззнаковое число 4 бита, для удобства

все его значения
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15

берем любое начало, допустим 7.
все значения от 8 до 15, не вызывают вопросов 8-7 = 1,... 15-7 = 8, честно получаем время прошедшие от 7 до текущего значения.

идем дальше, счетчик переполнился и получилось
0, 0 - 7 == -7, как это представлено в битах? 1001, а что это в беззнаковом числе? О чудо это 9

15-7 = 8, 0 - 7 = 9, 1 - 7 == - 6 (1010) == 10 и так далее, до

6 - 7 = -1 (1111) = 15;

то есть до полного цикла счетчика все переполнения отрабатываются правильно)
Go to the top of the page
 
+Quote Post
Ruslan-maniak
сообщение Oct 28 2014, 11:01
Сообщение #26


Частый гость
**

Группа: Участник
Сообщений: 92
Регистрация: 27-12-12
Из: Томск
Пользователь №: 74 999



Вот взяли мы это 7, и хотим что бы таймер сработал когда счётчик дойдёт до 12. И вы предлагаете вычитать 12 - 7 и сравнивать это с нулём, но так случилось что итерация 12 - 12 не случилась 12 - 11, а за ней уже 12 - 13, и та и другая даёт результат большей нуля в битовом выражении. И получается таймер не сработал тогда когда нужно. Разве нет?

Сообщение отредактировал Ruslan-maniak - Oct 28 2014, 11:01
Go to the top of the page
 
+Quote Post
ViKo
сообщение Oct 28 2014, 11:06
Сообщение #27


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Не так (я неправильно написал выше). Вам нужен интервал 5 (12 - 7). Текущее (стартовое) значение 7, запоминаете его. Дальше читаете значение таймера, отнимаете запомненное стартовое, и сравниваете разность с нужным интервалом.
Go to the top of the page
 
+Quote Post
Ruslan-maniak
сообщение Oct 28 2014, 11:14
Сообщение #28


Частый гость
**

Группа: Участник
Сообщений: 92
Регистрация: 27-12-12
Из: Томск
Пользователь №: 74 999



Но таким образом на каждый случай приходится по 2 переменных: стартовое время и интервал. Если же использовать приведение разности (значение срабатывания - счётчик) к знаковому типу и сравнения получившегося с нулём, то одна переменная.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Oct 28 2014, 11:24
Сообщение #29


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Тогда потеряете половину диапазона.
Go to the top of the page
 
+Quote Post
Ruslan-maniak
сообщение Oct 28 2014, 11:30
Сообщение #30


Частый гость
**

Группа: Участник
Сообщений: 92
Регистрация: 27-12-12
Из: Томск
Пользователь №: 74 999



Да я как-то не рассчитываю использовать интервал более 25 дней sm.gif



Сообщение отредактировал Ruslan-maniak - Oct 28 2014, 11:31
Go to the top of the page
 
+Quote Post
scifi
сообщение Oct 28 2014, 11:38
Сообщение #31


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(Ruslan-maniak @ Oct 28 2014, 14:14) *
Если же использовать приведение разности (значение срабатывания - счётчик) к знаковому типу и сравнения получившегося с нулём, то одна переменная.

Кстати, стандарт языка Си говорит, что переполнение знаковых целых - это "undefined behaviour", в отличие от беззнаковых, где всё хорошо в этом плане.

Цитата(Ruslan-maniak @ Oct 28 2014, 14:30) *
Да я как-то не рассчитываю использовать интервал более 25 дней sm.gif

Ну тогда вставьте в код assert(days <= 25). Когда наступите на эти грабли, хотя бы табличка перед носом будет :-)
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Oct 28 2014, 12:07
Сообщение #32


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



да тут не вопрос диапазона, а вопрос постановки задачи....

ожидание конкретного времени == выдерживанию интервала. А интервал вычисляется без потери диапазона, но требует доп. переменной, то есть вам приходиться хранить Interval == (NeedTime - Start) и Start. Вроде как 4 байта при современных объемах памяти не большая беда...

Go to the top of the page
 
+Quote Post
ViKo
сообщение Oct 28 2014, 12:16
Сообщение #33


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Вычисляя разность между текущим значением таймера и начальным, мы сдвигаем точку отсчета в положение Start. И уже относительно нее определяем текущее значение таймера, и сравниваем с требуемым. Аналогичного эффекта можно добиться, если сбрасывать таймер перед запуском. Но так, как предложено, можно на одном таймере задавать сразу несколько задержек.
Go to the top of the page
 
+Quote Post
Ruslan-maniak
сообщение Oct 28 2014, 16:52
Сообщение #34


Частый гость
**

Группа: Участник
Сообщений: 92
Регистрация: 27-12-12
Из: Томск
Пользователь №: 74 999



Да, цель именно выжать максимальную оптимизацию как по времени так и по памяти. В нынешних железах это конечно не принципиально. Но просто хочет это мой внутренний перфекционист. А использовать таймер на 25 дней - это как-то странно по моему. Для таких масштабов есть RTC.
P.S. Да и топик стартер вопрашал именно про юзанье одного счётчика для неограниченного кол-ва таймаутов, задержек и т.п.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Oct 28 2014, 18:10
Сообщение #35


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Пипец! Не ожидал такого мусоленья здесь совершенно очевидных вещей... wacko.gif
Код
volatile u32 sysTimer;

void isr()
{
  sysTimer++;
}  

void func()
{
  ...
  u32 t = sysTimer;
  do {
  ...
  } while (sysTimer - t < (u32)TOUT); //выполнять до TOUT тактов sysTimer, с точностью == времени задержки одного прохода цикла
  ...
}
Go to the top of the page
 
+Quote Post
scifi
сообщение Oct 28 2014, 20:13
Сообщение #36


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(Ruslan-maniak @ Oct 28 2014, 19:52) *
Да, цель именно выжать максимальную оптимизацию как по времени так и по памяти. В нынешних железах это конечно не принципиально. Но просто хочет это мой внутренний перфекционист.

Получается, что это чисто теоретическое упражнение. И правильное решение одно: ассемблер.
А на практике за такие потуги надо очень больно бить по рукам, ибо, как известно, "преждевременная оптимизация - корень всех зол".

Цитата(Ruslan-maniak @ Oct 28 2014, 19:52) *
А использовать таймер на 25 дней - это как-то странно по моему. Для таких масштабов есть RTC.

Не спешите. В очень многих кортексах есть счётчик циклов DWT_CYCCNT, и он очень удобен для этих самых задержек. Причём в МК из серии LPC43xx с частотой 204 МГц он переполняется каждые 21 сек.
Go to the top of the page
 
+Quote Post
Ruslan-maniak
сообщение Oct 29 2014, 03:38
Сообщение #37


Частый гость
**

Группа: Участник
Сообщений: 92
Регистрация: 27-12-12
Из: Томск
Пользователь №: 74 999



jcxz, вы предложили то же самое: использовать 2 переменных. scifi, почему же она преждевременная? я оптимизировал конкретный конечный функционал, разобрался в вопросе до конца и тщательно вдоль и поперёк оттестировал решение. Побейте тогда по рукам ещё и создателей библиотек которые оптимизируют свои творения до применения в реальных проектах. Какая-то странная логика. Счётчик циклов использую для измерений требуемых максимальную точность (единицы или десятки микросекунд, в зависимости от частоты). Но при чём тут он, не понятно?

Сообщение отредактировал Ruslan-maniak - Oct 29 2014, 03:42
Go to the top of the page
 
+Quote Post
jcxz
сообщение Oct 29 2014, 04:54
Сообщение #38


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Ruslan-maniak @ Oct 29 2014, 09:38) *
jcxz, вы предложили то же самое: использовать 2 переменных.

Где Вы углядели 2-ю? Вроде всего одна: t.

Цитата(Ruslan-maniak @ Oct 29 2014, 09:38) *
Побейте тогда по рукам ещё и создателей библиотек которые оптимизируют свои творения до применения в реальных проектах.

scifi Вам дело говорит.
1. Кто занимается оптимизацией инкремента переменной wink.gif , не пишут реальных проектов.
2. Кто пишет реальные проекты, не занимаются оптимизацией инкремента.
Go to the top of the page
 
+Quote Post
Ruslan-maniak
сообщение Oct 29 2014, 05:31
Сообщение #39


Частый гость
**

Группа: Участник
Сообщений: 92
Регистрация: 27-12-12
Из: Томск
Пользователь №: 74 999



Считайте по пальцам из вашего примера: переменная "t" - РАЗ, переменная "TOUT" - ДВА. Про второй пункт вашего поста я промолчу.
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Oct 29 2014, 05:34
Сообщение #40


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



Давайте поглядим
Плюсы минусы вашей оптимизации

Минусы
1. Меньший диапазон возможных значений в 2 раза
2. Строго говоря есть необходимость отметить это в документации, и возможные ошибки при использовании функции тем кто не в курсе.
3. Поскольку потери случаются на длинном конце использования, то еще долгий процесс выявления ошибки
4. Необходимость кучи объяснений почему вы сделали так а не иначе в коде

Плюсы
1. Вы выиграли 4 байта памяти. Даже если взять древний проц с каким нибудь 2 КБайтами памяти, то вы выиграли ~0.2% ресурса с каждого таймера. Для обычных кортексов с 48 Кбайтами 0.008%

В целом неплохо потрудилисьwink.gif
Go to the top of the page
 
+Quote Post
Ruslan-maniak
сообщение Oct 29 2014, 05:44
Сообщение #41


Частый гость
**

Группа: Участник
Сообщений: 92
Регистрация: 27-12-12
Из: Томск
Пользователь №: 74 999



1. Вы реально использовали миллисекундный таймер для замера интервала времени больше 25 дней?! О_о
2. Относится к первому пункту.
3. Потери НЕ СЛУЧАЮТСЯ ни в теории, ни на практике - провёл огромное кол-во тестов. Если вы считаете что возможны потери - приведите пример (буду искренне рад если вы поможете избежать этих потерь. если они возможны).
4. Кому и что нужно объяснять? По этой логике нужно объяснять и любой другой вариант.

1. Я писал что практическая ценность никакая от этого. Но именно это решение является решением для задачи поставленной топикстартером.

Сообщение отредактировал Ruslan-maniak - Oct 29 2014, 05:45
Go to the top of the page
 
+Quote Post
jcxz
сообщение Oct 29 2014, 08:13
Сообщение #42


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Ruslan-maniak @ Oct 29 2014, 11:31) *
Считайте по пальцам из вашего примера: переменная "t" - РАЗ, переменная "TOUT" - ДВА. Про второй пункт вашего поста я промолчу.

С чего вы взяли что TOUT это обязательно переменная???
Под TOUT имелось в виду выражение. Откройте любой учебник по си чтобы узнать значение термина expression.
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Oct 29 2014, 08:53
Сообщение #43


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



1. Почему нет, я участвовал в разработке системы которая работала автономно несколько лет без сбоев, повисаний, перезагрузок. При этом у нее был миллисекундный таймер для внутреннего времени (по ряду причин РТС использовать было нельзя), и почему бы раз в месяц этой системе не синхронизировать с центром время, данные и прочее?
1.1. Вы пишите что-то только один раз? На реюзинг не рассчитываете? Почему вы уверены что ваш код не запустят для микросекундного или наносекундного таймера?

2. Вы не застали замечательную ошибку паскаля который для delay в начале работы программы делал калибровку. Он брал цикл в сколько-то тактов и считал сколько милсекунд ушло на него, потом делил одно на другое и получал калиброванное значение чтобы точнее делать delay. Где то в районе 90 годов, все программы сделанные на этом паскале хором перестали работать. Потому что частота процов так возросла, что отведенный цикл стал выполнятся за 0 мСек, и деление на 0 давало ошибку. Уверен что те кто писал библиотечную функцию тоже заложились что процы же не станут в 1000 раз быстрее)

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

3. Сделайте вашим методом паузу больше половины интервала. Там можно так исхитриться что при заданной частоте проверок и интервале, оно будет так переполнятся что в 90% случаев все будет ок, а в 10% будет второй круг. И его ловить - это задача с подвохом...

4. странные и не очевидные ходы требует больше слов для их оправдания...


решение для ТС приведено сразу же в начальных постах, оно его устроило и оно является очевидно правильным.
Go to the top of the page
 
+Quote Post
Integro
сообщение Apr 1 2015, 08:55
Сообщение #44


Частый гость
**

Группа: Свой
Сообщений: 167
Регистрация: 25-12-09
Из: Минск
Пользователь №: 54 460



Цитата(scifi @ Jan 24 2014, 13:49) *
+1. Кстати, стандарт Си гарантирует, что при вычитании (unsigned int) - (unsigned int) результат будет корректным, пока разница во времени не превышает те самые 50 дней (для 32 бит), несмотря на переполнение первой или второй переменной.


У меня тут тоже с коллегами разгорелся спор, можно ссылку на стандарт с упоминанием этой гарантии, не могу найти.
Go to the top of the page
 
+Quote Post
SSerge
сообщение Apr 1 2015, 10:16
Сообщение #45


Профессионал
*****

Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528



Цитата(Integro @ Apr 1 2015, 15:55) *
У меня тут тоже с коллегами разгорелся спор, можно ссылку на стандарт с упоминанием этой гарантии, не могу найти.

В стандарте С (6.2.5.9) есть такой текст:
Цитата
The range of nonnegative values of a signed integer type is a subrange of the
corresponding unsigned integer type, and the representation of the same value in each
type is the same.33)A computation involving unsigned operands can never overflow,
because a result that cannot be represented by the resulting unsigned integer type is
reduced modulo the number that is one greater than the largest value that can be
represented by the resulting type.

А стандарт С++ в (3.9.1) содержит такой текст:
Цитата
Unsigned integers shall obey the laws of arithmetic modulo 2n where n is the number of bits in the value
representation of that particular size of integer.

и ниже примечание, совпадающее по смыслу с текстом из стандарта С, про арифметику по модулю 2n.

Впрочем всё это фигня и словесная эквилибристика.
А правда жизни состоит в том, что все эти свойства и поведение знаковых и беззнаковых типов диктуются устройством АЛУ и принятым в подавляющем большинстве современных машин представлением знаковых целых в так называемом "двоичном коде с дополнением до 2".
Преимущество такого представления - то что АЛУ работает совершенно одинаково, а разница signed/unsigned учитывается только при интерпретации признаков переполнения и переноса ( C и V ), и при многоразрядной арифметике, для правильно учёта переноса из младшего слова в старшее.
Изначально С неявно предполагал именно такое представление целых (как и сделано в PDP-11, на которых он изначально появился). Альтернативные представления уже тогда были редкостью.
Все более поздние изменения стандартов в части целочисленной арифметики и сдвигов просто витиевато выражают простую мысль: "делайте что хотите, но результат должен быть такой же как на "нормальных" процессорах использующих код с дополнением до двойки".

То есть сначала было придумано АЛУ, работающее с неотрицательными целыми числами, потом придумано как представлять отрицательные числа так, чтобы не переделывать АЛУ, а уж потом сочинители стандартов попытались описать что получилось так как они умеют это делать.


--------------------
Russia est omnis divisa in partes octo.
Go to the top of the page
 
+Quote Post
Integro
сообщение Apr 1 2015, 11:50
Сообщение #46


Частый гость
**

Группа: Свой
Сообщений: 167
Регистрация: 25-12-09
Из: Минск
Пользователь №: 54 460



Цитата(SSerge @ Apr 1 2015, 13:16) *

Спасибо за ответ, я уже так же нашел пару сносок на буржуйских форумах.
Go to the top of the page
 
+Quote Post
SSerge
сообщение Apr 1 2015, 14:13
Сообщение #47


Профессионал
*****

Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528



Почитал ради интереса библиотеки stm32cubef4.
Там есть замечательная функция void HAL_Delay(__IO uint32_t Delay) и куча мест где таймауты проверяются прямо в коде аналогичным образом.
Тех кто рискнёт пользоваться этим "программным продуктом" ждёт жестокий облом через 49 дней, 17часов, 2 минуты и 47 секунд.
Повбивав би ...

Моя версия таймера:
Код
extern "C" uint32_t GetTime(); // возвращает системное время, 1тик=1мс

class Csofttimer
{
    uint32_t Timeout;
public:
    bool timeout(){return (int)(Timeout-GetTime()) <= 0;  };
    void settimer(uint32_t time){Timeout = GetTime()+time;};
};


--------------------
Russia est omnis divisa in partes octo.
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Apr 1 2015, 15:51
Сообщение #48


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



Цитата
У меня тут тоже с коллегами разгорелся спор, можно ссылку на стандарт с упоминанием этой гарантии, не могу найти.

нафига стандарт то?
просто вычтите одно без знаковое из другого, и посмотрите что получилось в итоге если считать результат без знаковым.
Это гарантия не стандарта, а устройства числа...
Go to the top of the page
 
+Quote Post
scifi
сообщение Apr 1 2015, 19:28
Сообщение #49


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(Golikov A. @ Apr 1 2015, 18:51) *
нафига стандарт то?
просто вычтите одно без знаковое из другого, и посмотрите что получилось в итоге если считать результат без знаковым.

Да! Только хардкор, только реверс-инжиниринг языка Си! disco.gif
Мануалы придумал трус! 08.gif
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Apr 1 2015, 19:44
Сообщение #50


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



Причем тут это?
Покажите мне место в стандарте где написано что 2+4=6?
или место где написано 2+4=4+2

есть вещи которые описаны не стандартом а здравым смыслом и физикой природы...
так вот на пальцах

если у нас есть без знаковое от 0 до 15
2 - 12 = -10
а -10 имеет представление 0x6, что в без знаковом представлении просто 6, а теперь считаем сколько прошло с 12 до 2..
13 14 15 0 1 2 - вот и ответ... 6.
Так факт того что без знаковые не переполняются это свойства представления числа и принципов работы арифметики в компутере, а не стандарт языка...
Go to the top of the page
 
+Quote Post
Integro
сообщение Apr 1 2015, 20:25
Сообщение #51


Частый гость
**

Группа: Свой
Сообщений: 167
Регистрация: 25-12-09
Из: Минск
Пользователь №: 54 460



Да, я полностью с вами согласен, но аргумент "здравый смысл" в моем случае не прокатил, да и не професcиональный аргумент, поэтому мне понадобилось хоть какое-то сноски.
Go to the top of the page
 
+Quote Post
scifi
сообщение Apr 1 2015, 21:26
Сообщение #52


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(Golikov A. @ Apr 1 2015, 22:44) *
есть вещи которые описаны не стандартом а здравым смыслом и физикой природы...

Ага, "физика природы". А как насчёт порядка вычисления операндов в выражении? А если стандарт говорит, что этот порядок в данном случае не определён? А реверс-инжиниринг показал какой-то порядок? А завтра порядок изменился, потому что фаза Луны сменилась или что-то в этом духе? Может быть, лучше было мануал почитать?
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Apr 2 2015, 06:40
Сообщение #53


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



Вам нравиться слово реверс инжиниринг?

Данный вопрос не имеет отношения к экспериментальному установлению истины, которую и я считаю весьма зыбкой в условиях проф разработки.

Если на данный вопрос и есть ответ то не в стандартах С, а в стандартах представления двоичного числа и реализации операции вычитания.

ответ добывается так
1. представление числа в 2-ичном виде. Берем 2 числа, и 4 битную арифметику, числа 2 и 12 представляются как 0010 и 1100 - надеюсь тут не будет ремарки про реверс инжиниринг? Документальное подтверждение что числа представляются так надо искать в разделах математики.
2. Реализация вычитания, как сложение с дополнительным кодом числа. Тут опять я надеюсь обойдемся без реверс инжиниринга, документальное подтверждение не знаю где, в каких то книгах по информатики
и того 2 - 12 == 2 + @12 так я обозначил доп код 12.
2 == 0010, @12 == @1100 == (~(1100) + 1) == 0011 + 1 == 0100
3. Сложение 2 ичных числе, документальное подтверждение в разделах математики, реверс инжиниринг не применяем

2 - 12 == 2 + @12 == 0010 + @1100 == 0010 + 0100 == 0110 = 6


Теперь у меня вопрос к реверс инжинеру, что я сделал не так?

В данном конкретном случае просто так получается, это здравый смысл физики нашей природыsm.gif))) и никакого реверса...


Со знаковыми так не выходит, потому что в 4 битах у них только пол диапазона, то есть дойдя до 0111 до 7, они пойдут дальше до 1000, но в знаковом это -8. Надо понять главное это все представление чисел, это не их значения. Значения у них всегда одно оно не меняется, просто мы решили что 1000 - это -8 для знакового и 8 для без знакового, просто решили все операции происходят с двоичным исходником, всегда одинаково.

То есть важно понять что нет никакой магии или особо указания в том что мы вычитаем именно без знаковые, компилятор не делает ничего особенного увидев эту запись, он делает все те же операции что и обычно, просто результат представляет по другому. Получив в ходе вычитания 1000 для знакового результата он скажет что это -8, а для без знакового скажет что это +8 и все!
Go to the top of the page
 
+Quote Post

4 страниц V   1 2 3 > » 
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 29th July 2025 - 02:29
Рейтинг@Mail.ru


Страница сгенерированна за 0.01871 секунд с 7
ELECTRONIX ©2004-2016