Random для Attiny13
- Войдите на сайт для отправки комментариев
Втр, 18/01/2022 - 21:09
Здравствуйте. Вопрос, есть вот такой компактный кусок кода для Attiny13, который занимает мало места и достаточно хорошо генерирует псевдо-рандом, выдавая значения от 0 до 7:
byte rnd() { static uint16_t seed; seed = (seed * 2053ul) + 13849; return (seed >> 8) & 7; }
Как его изменить, что бы числа выпадали от 1 до 6?
Понимаю, что после битового И в конце можно поставить 6 и тогда считает до шести, но от нуля.
Как сделать сдвиг или доп. условие что бы счёт шёл от одного до шести.
Спасибо.
сравнивать на 0 и запускать генерацию по новой, по другому наврядли
Да нифига нельзя ставить 6. Тут 7 это маска, где три младших бита равны единицам. А если вместо 7 воткнуть 6, то результаты будут 2,4,6 и все. Поэтому разумный совет при нуле или семи перезапрашивать результат у процедуры.
Или, как уже сказали, выкинуть операции сдвига и наложения битовой маски и использовать остаток от деления на 6 (%6) , тогда будешь получать значения от 0 до 5 и добавлять единицу.
Спасибо за помощь. Поигравшись с цифрами в итоге сделал так:
Проследив за значениями, повторения получились достаточно рандомные.
Спасибо за помощь. Поигравшись с цифрами в итоге сделал так:
Проследив за значениями, повторения получились достаточно рандомные.
а что статистика говорит?
Всё же вернул сдвиг на 8, так более равномерное выпадание.
Вот что получилось за 10 прогонов:
Каждые 6-7 прогонов есть сильно отличающиеся результаты, но для моих целей это не так важно. Большое спасибо за помощь.
на большом количестве генераций цифры 5 и 6 выпадают реже
Рандомность это не только количество значений, но куча других критериев. Честно говоря не разобрался как запускать существующие тесты.
Для данного алгоритма - если учитывать только количество значений, то лучше чем >>7 и >>8 получается если
return ((seed / 254) % 6) + 1);
А еще ровнее если вообще не делить
return ((seed % 6) + 1);
Столкнулся с проблемой о которой не подумал изначально. Сброс Attiny13 идёт через Reset, а следовательно и псевдо-рандом всегда начинается с одних и тех же значений, так как код выполняется 1 раз и Attiny уходит в вечный сон до сброса.
Все выводы заняты, с аналогового вывода взять помехи не получится, зато имеется EEPROM. Reset будет не так часто нажиматься, поэтому ресурса одной ячейки хватит за глаза.
Можно считывать значение с EEPROM, произвести расчёт рандомного числа, затем прибавить +1 и потом записать в EEPROM.
Вот только проблема, не получается всё это совместить, есть идеи у кого нибудь?
Не понял, что не удается совместить. Вы вроде все расписали. Храните счетчик запусков в ячейке, при старте увеличиваете на 1.
Так как математики из нас никакие, то чисто опытным путем посмотрите - устроит ли вас рандомность если просто брать начальный seed не всегда 0 а последовательно 0, 1, 2, 3 ... 255, 0, 1 ...
Подумав, получилось вот так:
Квалификатор static убрал, так как код будет выполняться 1 раз и далее вечный сон до перезагрузки, а 22 байта лишними не будут. Вот такие значения более менее рандомные после десятка прогона.
Вот такая картина получилась при запуске с пустой ячейки EEPROM:
Использовал EEPROM: get и put вместо read и write, так хоть и больше занимается Flash, тем не менее проще разместить большие числа в EEPROM и рандом более равномерный.
Если есть замечания, буду рад им.
Можно считывать значение с EEPROM, произвести расчёт рандомного числа, затем прибавить +1 и потом записать в EEPROM.
Вы забыли написать, что именно Вы собираетесь записывать в EEPROM. Судя по тому, что собираетесь прибавлять по 1, совсем не то, что нужно.
А нужно - seed.