|
|
  |
Простой ГСП на Си |
|
|
Guest_TSerg_*
|
Jan 17 2014, 19:28
|
Guests

|
Любой RNG на основе сдвигового регистра 8 р, но лучше - 16 р  u8 rnd8(void) { static u16 seed = 0; seed = (seed << 7) - seed + 251; return (u8)(seed + (seed>>8)); }
|
|
|
|
|
Jan 17 2014, 19:50
|

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

|
Спасибо, коллеги за скорую помощь! Цитата(TSerg @ Jan 17 2014, 21:28)  Любой RNG на основе сдвигового регистра 8 р, но лучше - 16 р  u8 rnd8(void) { static u16 seed = 0; seed = (seed << 7) - seed + 251; return (u8)(seed + (seed>>8)); } Я только не пойму, если в теле функции переменная seed каждый раз обнуляется, то какой смысл в static?
|
|
|
|
|
Jan 17 2014, 22:04
|

Гуру
     
Группа: Модераторы
Сообщений: 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; }
|
|
|
|
|
Jan 18 2014, 07:38
|
Гуру
     
Группа: Свой
Сообщений: 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.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|