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

 
 
4 страниц V   1 2 3 > »   
Reply to this topicStart new topic
> Простой ГСП на Си
Herz
сообщение Jan 17 2014, 19:13
Сообщение #1


Гуру
******

Группа: Модераторы
Сообщений: 10 983
Регистрация: 23-11-05
Пользователь №: 11 287



Предположим, требуется моргать светодиодом с псевдослучайным интервалом от 2 до 30 секунд.
Посоветуйте простую функцию на Си для генерации целых чисел в таком малом диапазоне. Пусть от 1 до 255 максимум.
Функция rand() из библиотеки HT-PICC тяжеловата как-то...
Go to the top of the page
 
+Quote Post
thermit
сообщение Jan 17 2014, 19:21
Сообщение #2


Знающий
****

Группа: Участник
Сообщений: 781
Регистрация: 3-08-09
Пользователь №: 51 730



x(n)=(1664525*x(n-1)+32767) mod 2^32 и берем старшие N бит.
Go to the top of the page
 
+Quote Post
Guest_TSerg_*
сообщение Jan 17 2014, 19:28
Сообщение #3





Guests






Любой RNG на основе сдвигового регистра 8 р, но лучше - 16 рsm.gif

u8 rnd8(void)
{
static u16 seed = 0;

seed = (seed << 7) - seed + 251;

return (u8)(seed + (seed>>8));
}
Go to the top of the page
 
+Quote Post
Herz
сообщение Jan 17 2014, 19:50
Сообщение #4


Гуру
******

Группа: Модераторы
Сообщений: 10 983
Регистрация: 23-11-05
Пользователь №: 11 287



Спасибо, коллеги за скорую помощь! biggrin.gif

Цитата(TSerg @ Jan 17 2014, 21:28) *
Любой RNG на основе сдвигового регистра 8 р, но лучше - 16 рsm.gif

u8 rnd8(void)
{
static u16 seed = 0;

seed = (seed << 7) - seed + 251;

return (u8)(seed + (seed>>8));
}

Я только не пойму, если в теле функции переменная seed каждый раз обнуляется, то какой смысл в static?
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Jan 17 2014, 19:52
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(Herz @ Jan 17 2014, 23:50) *
Я только не пойму, если в теле функции переменная seed каждый раз обнуляется, то какой смысл в static?

Она не обнуляется, 0 присваивается только при инициализации программы, т.е. до первого вызова.
Go to the top of the page
 
+Quote Post
Herz
сообщение Jan 17 2014, 20:04
Сообщение #6


Гуру
******

Группа: Модераторы
Сообщений: 10 983
Регистрация: 23-11-05
Пользователь №: 11 287



Цитата(aaarrr @ Jan 17 2014, 21:52) *
Она не обнуляется, 0 присваивается только при инициализации программы, т.е. до первого вызова.

Отлично, спасибо! А можно ли немного усложнить задачу и передавать аргументами в функцию желаемый диапазон значений?
Go to the top of the page
 
+Quote Post
SM
сообщение Jan 17 2014, 20:49
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881



интервал определен как [offset, offset+max)

два варианта:

1) - два параметра, max и offset

return ((rand_value) % max) + offset;

это если % достаточно легковесный.

2) - три параметра, mask, max и offset, mask ближайшее значение типа 2^n-1, большее или равное max

temp = rand_value & mask;
if (temp >= max) temp -= max;
return temp + offset;

это без операции деления, вероятно менее затратный вычислительно.

rand_value - результат вышеприведенной ф-ции.
Go to the top of the page
 
+Quote Post
Herz
сообщение Jan 17 2014, 22:04
Сообщение #8


Гуру
******

Группа: Модераторы
Сообщений: 10 983
Регистрация: 23-11-05
Пользователь №: 11 287



Спасибо, SM!
Но, по правде говоря, ничего не понял.
Вас на затруднит немного разжевать?
Вот если у меня есть две переменные:
Код
unsigned char min = 2;
unsigned char max = 30;


и я вызываю функцию

unsigned char rand(a, b ) :

result = rand(min, max);

желая получить число в указанном диапазоне. Как должно выглядеть её тело?
Так?
Код
unsigned char rand(a, b)
{
static unsigned int rand_value
return (unsigned char)((rand_value) % b) + a;
}
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jan 18 2014, 07:30
Сообщение #9


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Код
u8 rnd8(u8 min, u8 max)
{
   static u16 seed = 0;
   u8 tmp;

   seed =(seed << 7) - seed + 251;
   tmp = (u8)(seed+ (seed>>8));

   while( tmp > max) tmp-=max;// для данного случая это будет всегда выигрышнее, чем  целочисленное деление

return tmp + min;
}


Go to the top of the page
 
+Quote Post
SM
сообщение Jan 18 2014, 07:38
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881



Цитата(Herz @ Jan 18 2014, 02:04) *
Вас на затруднит немного разжевать?

желая получить число в указанном диапазоне. Как должно выглядеть её тело?




Если за базу взять ф-цию, предложенную TSerg, то вот так:

медленный код (он притащит библиотечную ф-цию деления с остатком):

суть - тупое вычисление в лоб остатка от деления ограничиваемого числа на max.

Код
u8 rnd8(u8 max, u8 offset)
{
static u16 seed = 0;
u8 temp;

seed = (seed << 7) - seed + 251;

temp =  (u8)(seed + (seed>>8));

return (temp % max) + offset;

}


самый быстрый код, но требующий маски, которая задается параметром ф-ции, и должна быть числом 2^n-1, ближайшим, больше либо равным "max".

Суть кода - операция лог. И с маской, соответствующей требованию ближайшего, большего либо равного 2^n-1, к max, ограничивает значение неким числом 2^n-1, меньшим max*2, затем в одну итерацию вычитания по условию, число ограничивается уже max.

Если требуется вычисление маски во время выполнения, то есть "max" задается не константами, и требуется максимальная скорость, то можно добавить получение маски по таблице (массиву констант на 256 значений - тут уж хотите быстро, раскошеливайтесь на память для таблиц, другие способы вычисления такой маски на АВР в любом случае будут в цикле до 8 итераций в худшем случае)...


Код
u8 rnd8(u8 mask, u8 max, u8 offset)
{
static u16 seed = 0;
u8 temp;

seed = (seed << 7) - seed + 251;

temp =  ((u8)(seed + (seed>>8))) & mask;
if (temp >= max) temp -= max;

return temp + offset;

}



вот еще вариант, с операцией вычисления остатка от деления, реализованной в теле ф-ции без использования библиотечных ф-ций, средне производительный.

Суть - вычисление остатка от деления, как в первом варианте, но не "тупое в лоб", а умное, без лишних запчастей из библиотек, и без вычисления частного (которое по любому вычисляется библиотечной ф-цией, но отбрасывается при операции "%")


Код
u8 rnd8(u8 max, u8 offset)
{
static u16 seed = 0;

u8 temp, i;
u16 sub;

seed = (seed << 7) - seed + 251;

temp =  (u8)(seed + (seed>>8));

i=8; sub = max << 8;

do {
  sub >>= 1;
  if (sub >= temp) temp -= sub;
} while (--i);

return temp + offset;

}




Цитата(_Pasha @ Jan 18 2014, 11:30) *
для данного случая это будет всегда выигрышнее, чем целочисленное деление


Да щасссс... целочисленное деление всегда 8 итераций (см. мой третий вариант). А у вас.... прикиньте, например, для частного случая max = 3 и tmp=254.
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jan 18 2014, 08:05
Сообщение #11


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(SM @ Jan 18 2014, 11:38) *
Да щасссс... целочисленное деление всегда 8 итераций (см. мой третий вариант). А у вас.... прикиньте, например, для частного случая max = 3 и tmp=254.

А ну да, маску надо задавать.
Ага, и нафига там min в параметрах? Для красоты sm.gif


Сообщение отредактировал _Pasha - Jan 18 2014, 08:06
Go to the top of the page
 
+Quote Post
Herz
сообщение Jan 18 2014, 08:54
Сообщение #12


Гуру
******

Группа: Модераторы
Сообщений: 10 983
Регистрация: 23-11-05
Пользователь №: 11 287



Спасибо большое, есть что покурить.

Цитата(_Pasha @ Jan 18 2014, 10:05) *
Ага, и нафига там min в параметрах? Для красоты sm.gif

Ну, это пустяки. Если функция возвращает число в диапазоне от 0, то можно предварительно max задать уменьшенным на min, а потом к результату этот min добавить, как у Вас.
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jan 18 2014, 09:02
Сообщение #13


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(Herz @ Jan 18 2014, 12:54) *
Ну, это пустяки. Если функция возвращает число в диапазоне от 0, то можно предварительно max задать уменьшенным на min, а потом к результату этот min добавить, как у Вас.

Ага, кроме того что min должен быть передан в параметрах и на это доп. расходы могут накладываться. Не по сишному sm.gif
Вот из-за этих пустяков в мире всё тормозит.
Go to the top of the page
 
+Quote Post
SM
сообщение Jan 18 2014, 09:07
Сообщение #14


Гуру
******

Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881



Цитата(_Pasha @ Jan 18 2014, 13:02) *
что min должен быть передан в параметрах


ну раз в условиях задачи поставили ограничение по диапазону, а не только по макс. значению, значит, наверное, min нужен...
Go to the top of the page
 
+Quote Post
Herz
сообщение Jan 18 2014, 09:16
Сообщение #15


Гуру
******

Группа: Модераторы
Сообщений: 10 983
Регистрация: 23-11-05
Пользователь №: 11 287



Цитата(_Pasha @ Jan 18 2014, 11:02) *
Ага, кроме того что min должен быть передан в параметрах и на это доп. расходы могут накладываться. Не по сишному sm.gif
Вот из-за этих пустяков в мире всё тормозит.

Замечание правильное. В реальности такой необходимости нет пока. А условие я формулировал так для наглядности, чтобы самому было легче разобраться.
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 Текстовая версия Сейчас: 6th July 2025 - 02:55
Рейтинг@Mail.ru


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