|
|
  |
Простой ГСП на Си |
|
|
|
Jan 18 2014, 10:55
|

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

|
Странно, но вот у меня такая функция: Код unsigned char rnd8(unsigned char max) { static unsigned int seed = 0; unsigned char temp, i; unsigned int sub;
seed = (seed << 7) - seed + 251; temp = (unsigned char)(seed + (seed>>8)); i = 8; sub = max << 8;
do { sub >>= 1; if (sub >= temp) temp -= sub; } while (--i);
return temp; } (минимум опустил пока для простоты) при вызове: Код NUM = rnd8(MAX); где Код #define MAX 30 работает неверно. Диапазон не соблюдает. Более того, старший бит всегда 1.
|
|
|
|
|
Jan 18 2014, 11:30
|
Гуру
     
Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881

|
Цитата(Herz @ Jan 18 2014, 15:22)  Нет, я имею в виду, не возвращает ли функция int в этом случае вместо char после приведения? Или типом функции это задаётся строго? В контексте Вашего вопроса, приведения в "temp -= sub", это задается типом переменной temp, при присваивании в 8-битную переменную автоматически все лишнее обрезается, и оптимизатор, по идее, должен сам определить это, и использовать 8-битные операции для всего выражения (которое по ANSI должно было считаться в 16 битах, а потом обрезаться). Касаемо значения, возвращаемого функцией, да, оно строго задано типом в описании функции, и не может быть никаким, кроме заданного. UPD: PS по логике, кстати, в том выражении надо не temp приводить к типу sub, а наоборот, учитывая, что по условию там temp >= sub, что означает, что реальная разрядность числа в sub меньше либо равна 8. Т.е. для наглядности и для подсказки оптимизатору можно написать temp -= (u8) sub;
|
|
|
|
|
Jan 18 2014, 14:15
|
ʕʘ̅͜ʘ̅ʔ
    
Группа: Свой
Сообщений: 1 008
Регистрация: 3-05-05
Пользователь №: 4 691

|
Не нужно вам никакого деления и остатка от деления.
1. делаете генератор в полном диапазоне int16 или int8. с помощью LFSR. Вам написали.
2. рассматриваете выход генератора как fractional число Q1.15, если выход int16, или Q1.7, если выход int8. Таким образом у вас есть RNG с fractional выходом в диапазоне [-1; 1)
3. умножаем (fractional), прибавляем, сдвигаем, приводим типы (сделаете в удобной последовательности), чтобы получить нужный диапазон
можно обнулять старший бит и тогда на выходе RNG получать [0; 1). Дальнейшая арифметика в этом случае видится немного попроще. Будет, правда, слегка перекошенное распределение (для ненулевого числа x != 0 будет вероятность выпадения p(x); если же x = 0, то p(0) ~= 1.5*p(x) ), но для мигалки это не принципиально, мне кажется.
Итого: сдвиги, суммы, одно умножение
|
|
|
|
|
Jan 18 2014, 20:42
|
Гуру
     
Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881

|
Цитата(Fat Robot @ Jan 18 2014, 18:15)  одно умножение так вот в нем и зло. если нету ни аппаратного умножителя, ни аппаратного делителя, то и на умножение получим цикл на 8 итераций, и на нахождение остатка от деления тоже 8 итераций. При этом умножение, скорее, проиграет на 8-битном RNG и 8-битном процессоре по причине 16-битного суммирования в цикле против 8-битного вычитания, но выиграет - очень врядли (хотя, конечно, этот вопрос надо отдельно изучить, что оптимальнее на конкретной архитектуре). И при этом нахождение остатка не испортит распределение. Ну а если аппаратное умножение имеется, то тут, разумеется, совсем другой расклад по производительности. Но вроде в обычном PIC его и нету...
|
|
|
|
|
Jan 18 2014, 21:12
|

Lazy
     
Группа: Свой
Сообщений: 2 070
Регистрация: 21-06-04
Из: Ukraine
Пользователь №: 76

|
Цитата(Herz @ Jan 17 2014, 23:13)  Предположим, требуется моргать светодиодом с псевдослучайным интервалом от 2 до 30 секунд. Посоветуйте простую функцию на Си для генерации целых чисел в таком малом диапазоне. Пусть от 1 до 255 максимум. Функция rand() из библиотеки HT-PICC тяжеловата как-то... Что-то все все усложняют... На светодиод наверное человек смотреть будет? Так вот через несколько он забудет, что видел при этом моргании. Просто сделайте таблицу на пару минут и все... Или игровой автомат? Тогда запись на видео лишит всего дохода... П.С. Или Вам надо офигенно нормальное распределение? Увы - ничего не выйдет....
--------------------
"Everything should be made as simple as possible, but not simpler." - Albert Einstein
|
|
|
|
|
Jan 18 2014, 22:16
|

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

|
Цитата(Fat Robot @ Jan 18 2014, 16:15)  Не нужно вам никакого деления и остатка от деления. Сразили! Я и слов-то таких не знаю: fractional.  Буде Ваша воля пояснить свою идею попроще, постараюсь разобраться... Цитата(SM @ Jan 18 2014, 22:42)  Ну а если аппаратное умножение имеется, то тут, разумеется, совсем другой расклад по производительности. Но вроде в обычном PIC его и нету... На данном этапе имеется PIC18, в котором аппаратное умножение присутствует. Но хочется перенести проект на PIC16, где на эту задачу желательно потратить минимум ресурсов. Цитата(Victor® @ Jan 18 2014, 23:12)  Что-то все все усложняют... На светодиод наверное человек смотреть будет? Так вот через несколько он забудет, что видел при этом моргании. Просто сделайте таблицу на пару минут и все... Или игровой автомат? Тогда запись на видео лишит всего дохода... П.С. Или Вам надо офигенно нормальное распределение? Увы - ничего не выйдет.... Да нет, светодиод - это пример, упрощение. На самом деле нужно посылать некий сигнал, но нерегулярно. Чтобы не привыкнуть. Таблица отпадает - памяти маловато. Хотя... Но, от добра добра не ищут: пример от ув. SM очень даже ничего.
|
|
|
|
|
Jan 18 2014, 23:55
|
ʕʘ̅͜ʘ̅ʔ
    
Группа: Свой
Сообщений: 1 008
Регистрация: 3-05-05
Пользователь №: 4 691

|
Объясню предельно просто, не жонглируя терминологией Пусть генератор после всех преобразований имеет выход X в диапазоне [0; (2^n)-1] нужно и можно найти такие постоянные значения Y и Z, чтобы значение числа round((X*Y) >> Z) лежало в диапазоне [0; max-min] Все, что для этого нужно это (((max-min) * X ) + (1 << (n - 1))) >> n. Пусть n=7, a max-min=27 X в диапазоне [0; 127] ((X*27)+64)>>7 будет лежать в диапазоне [0;27] выход операции умножения 16 бит Если операции умножения у вас нет, но есть немного свободы в выборе значения для разности max-min, то нужно выбрать такое значение, чтобы в нем было как можно меньше единиц в двоичных разрядах, тогда умножение из общего случая упростится в сумму сдвигов. пусть вместо 27 из примера вас устроит 24 = (2^4) + (2^3), тогда преобразование будет таким: (( X << 4 ) + ( X << 3 ) + 64 )>>7 и выход будет лежать в диапазоне [0;24] Цитата(Herz @ Jan 18 2014, 23:16)  Буде Ваша воля пояснить свою идею попроще, постараюсь разобраться...
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|