реализация rand ()

Я пишу встроенный код на C, и мне нужно использовать функцию rand (). К сожалению, rand () не поддерживается в библиотеке для контроллера. Мне нужна простая реализация, которая быстрая, но, что более важно, имеет небольшие накладные расходы на пространство, которые производят относительно высококачественные случайные числа. Кто-нибудь знает, какой алгоритм использовать или пример кода?

РЕДАКТИРОВАТЬ: это для обработки изображений, поэтому «относительно высокое качество» означает приличную длину цикла и хорошие однородные свойства.


person rlbond    schedule 22.07.2009    source источник
comment
Что вы ищете более конкретно? Вам нужна большая продолжительность цикла? Насколько велики числа, о которых мы говорим (16-битные, 32-битные и т. Д.)? Насколько они должны быть случайными? Говоря о накладных расходах места, вы имеете в виду ограничения ПЗУ, ограничения ОЗУ или и то, и другое?   -  person David Thornley    schedule 22.07.2009
comment
Если у вас есть SysTick или что-то еще, которое можно использовать для подсчета времени от включения до текущего времени, вы можете использовать этот счетчик в качестве начального числа для некоторых из генераторов случайных чисел, показанных ниже.   -  person avra    schedule 02.07.2012
comment
Вот реализация Mersenne Twister в классе C ++.   -  person bobobobo    schedule 03.08.2015


Ответы (11)


Ознакомьтесь с сборником генераторов случайных чисел от Джорджа Марсальи. Он ведущий эксперт в области генерации случайных чисел, поэтому я буду уверен, что использую все, что он порекомендует. Генераторы в этом списке крошечные, для некоторых требуется всего пара длинных длин без знака в качестве состояния.

Генераторы Marsaglia, безусловно, «высокого качества» по вашим меркам, с длительным сроком службы и хорошим равномерным распределением. Они проходят строгие статистические тесты, но не подходят для криптографии.

person John D. Cook    schedule 22.07.2009
comment
Спасибо за ссылку на это. Я провел небольшое исследование и нашел KISS: немного слишком просто, от Грега Роуза который (а) предупреждает о плохих начальных значениях в MWC и (б) ставит под сомнение генератор SHR3. В этом сообщении 2003 г. Марсаглии приведен немного другой SHR3, который устраняет проблемы. у более раннего. Я был бы счастлив использовать генератор в стиле KISS, если я проверяю и избегаю плохих семян и гарантирую, что использую лучший генератор SHR3. - person Craig McQueen; 20.01.2011
comment
Марсалья внес значительный вклад в развитие ГПСЧ в 90-е годы, однако сегодня, я думаю, я бы посмотрел на Л'Экуайера или Мацумото. При этом, если OP не выполняет серьезную симуляцию на своих встроенных устройствах, я думаю, что можно использовать и большинство более ранних хороших генераторов :-) - person Joey; 26.01.2011
comment
@Joey: Генераторы KISS Марсаглии по-прежнему хорошо работают в L'Ecuyer's TestU01 RNG tests, пройдя тесты, которые даже некоторые собственные генераторы случайных чисел L'Ecuyer, такие как LFSR113, терпят неудачу. - person Craig McQueen; 21.02.2011

Используйте код C для LFSR113 от L'écuyer:

unsigned int lfsr113_Bits (void)
{
   static unsigned int z1 = 12345, z2 = 12345, z3 = 12345, z4 = 12345;
   unsigned int b;
   b  = ((z1 << 6) ^ z1) >> 13;
   z1 = ((z1 & 4294967294U) << 18) ^ b;
   b  = ((z2 << 2) ^ z2) >> 27; 
   z2 = ((z2 & 4294967288U) << 2) ^ b;
   b  = ((z3 << 13) ^ z3) >> 21;
   z3 = ((z3 & 4294967280U) << 7) ^ b;
   b  = ((z4 << 3) ^ z4) >> 12;
   z4 = ((z4 & 4294967168U) << 13) ^ b;
   return (z1 ^ z2 ^ z3 ^ z4);
}

Очень качественно и быстро. НЕ используйте rand () ни для чего. Это хуже, чем бесполезно.

person Community    schedule 24.07.2009
comment
Обратите внимание, что он предполагает 32-битное int, что может не подходить для встроенной платформы. - person tomlogic; 07.06.2011
comment
Почему именно это случайно? - person me me; 02.05.2013
comment
мне, мне, это зависит от того, что вы подразумеваете под случайным. LFSR RNG основаны на четко определенной математической повторяемости с известным периодом и хорошими статистическими свойствами (воспринимаемой случайностью). Если вы не берете энтропию из какого-либо физического явления (например, линейного шума), любой используемый вами ГСЧ будет аналогичным псевдослучайным. (Криптографически безопасные ГСЧ более сложные, но все же псевдослучайные). Более сильный Mersenne Twister - это скрученный GFSR, поэтому он связан с вышеизложенным, а более слабый Xorshift - это частный случай LFSR. CMWC RNG может быть как быстрее, так и сильнее, чем любой из них. - person Mike S; 19.07.2013
comment
@me me: это псевдослучайные переменные, статические переменные содержат начальные значения. Он всегда возвращает одну и ту же последовательность чисел. - person k3a; 19.07.2015
comment
Вероятно, было ошибкой помещать семя в ответ как статическое, но это выглядит многообещающим, просто убедитесь, что вы предоставили семя извне. Я попытаюсь. Что касается 32-битного, фактический источник использует uint32_t вместо unsigned int, так что это тоже не должно быть проблемой. - person AlexKven; 18.08.2018

Вот ссылка на ANSI C реализацию нескольких генераторов случайных чисел.

person Reed Copsey    schedule 22.07.2009

Я сделал коллекцию генераторов случайных чисел «simplerandom», которые компактны и подходят для встроенных систем. . Коллекция доступна на C и Python.

Я поискал вокруг кучу простых и достойных, которые смог найти, и собрал их в небольшой пакет. В их число входят несколько генераторов Marsaglia (KISS, MWC, SHR3) и пара генераторов L'Ecuyer LFSR.

Все генераторы возвращают 32-битное целое число без знака и обычно имеют состояние от 1 до 4 32-битных целых чисел без знака.

Интересно, что я обнаружил несколько проблем с генераторами Marsaglia и попытался исправить / улучшить все эти проблемы. Вот эти проблемы:

  • Генератор SHR3 (компонент генератора KISS от Marsaglia 1999 года) был сломан.
  • Младшие 16 битов MWC имеют период примерно 2 29,1. Итак, я сделал немного улучшенный MWC, который дает младшим 16 битам период 2 59,3, который является общим периодом этого генератора.

Я обнаружил несколько проблем с заполнением и попытался создать надежные процедуры заполнения (инициализации), чтобы они не сломались, если вы дадите им "плохое" значение начального числа.

person Craig McQueen    schedule 05.10.2011
comment
Это более старый пост, но я хочу внести поправку: младшие 16 бит генератора MWC 2x16 Marsaglia на самом деле имеют период 589823999 = 2 ^ 29.1357092836584, а не 2 ^ 16. (Это возможно, потому что имеется 32 бита состояния, включая перенос.) Период - это порядок b mod p, где b = 2 ^ 16 и p = 18000 * 2 ^ 16 - 1. Порядок = 589823999 = (p - 1) / 2 в этом случае. Лучшее, что вы можете сделать с базовым 65536 MWC и 16-битным множителем, - это период 2 ^ 30,9990971519312 с множителем 65495. Лучшее безопасное простое число - 65184, что дает период 2 ^ 30,9922302642905. - person Mike S; 19.07.2013
comment
Старшие биты генератора MWC 2x16 Марсальи имеют период 1211400191 = 2 ^ 30,1740283979574, а младшие биты имеют период 589823999 = 2 ^ 29,1357092836584. Объединение этих двух слов имеет период 714512905044983809 = 2 ^ 59.3097376816159, но отдельные высокие и низкие слова все еще имеют независимые низкие периоды. Ваш модифицированный MWC2 увеличивает качество вывода младших битов, не нарушая математической основы базового генератора, делает период младших битов таким же, как и общая комбинация, а также помогает старшим битам ... но я не уверен на сколько. - person Mike S; 19.07.2013
comment
Да, вы совершенно правы. Я сказал, что младшие 16 бит MWC имеют только период 2 ^ 16, но я должен был сказать период 2 ^ 29,1. Я отредактировал это соответствующим образом. Но я не думаю, что мои изменения в MWC2 имеют какое-либо значение для старших битов. - person Craig McQueen; 19.07.2013
comment
Разница, которую вносят ваши изменения в старшие биты, незначительна: когда вы добавляете старшие биты и младшие биты, иногда это переносит еще 1 бит в старшие биты, тем самым слегка изменяя старшие биты примерно в половине случаев. На самом деле, я изначально ошибался насчет периода старших битов: я сказал, что у них есть независимый период 2 ^ 30,1740283979574, но на самом деле у них есть полный период 2 ^ 59,3097376816159, потому что Марсалья уже строил их из сложения младшие 16 бит znew и старшие 16 бит wnew. Последнего я сначала не заметил. - person Mike S; 20.07.2013
comment
У меня создалось впечатление, что ваши изменения улучшат период старших битов, а также младших битов (случайность, не так уж и много), но поскольку у старших битов уже был полный период, это не имеет особого значения. : p На самом деле, я только что сделал еще одну ошибку в своем последнем комментарии: переносимый 1-бит будет происходить гораздо реже, чем в половине случаев ... только иногда. Кстати, хороший улов, обнаружив очень плохие семена с MWC. Хотя немного пугает то, что они, похоже, не соответствуют очевидному шаблону, который можно было бы обобщить на другие генераторы MWC ... - person Mike S; 20.07.2013
comment
К сожалению, я только что понял, что все обнаруженные вами плохие семена превышают максимальное значение, которое могут генерировать генераторы base-65536, но исходное значение для Lag-1 MWC устанавливает значение последнего возврата по указу. Поскольку генератор base-65536 может возвращать только значение ‹= 65535, очевидно, что некоторые большие начальные значения могут привести к некорректному поведению. Сам Марсаглия также использовал более крупные семена для этого генератора, но мне интересно, следует ли в первую очередь ограничивать их (исходный% семян). В остальном плохие начальные состояния кажутся более предсказуемыми. - person Mike S; 20.07.2013
comment
Как оказалось, плохие семена ›65536 на самом деле приводят к другому плохому состоянию, о котором я упоминал: где последнее возвращаемое значение = max (в данном случае 65535), а перенос - это множитель - 1. Это своего рода облегчение. , потому что, по крайней мере, он демонстрирует закономерность. :) - person Mike S; 20.07.2013

Я рекомендую научную статью Две быстрые реализации генератора минимальных стандартных случайных чисел автора Давид вольностей. Вы можете найти бесплатный PDF через Google. Также стоит прочитать оригинальную статью о генераторе минимальных стандартных случайных чисел.

Код Carta дает быстрые высококачественные случайные числа на 32-битных машинах. Для более тщательной оценки см. Статью.

person Norman Ramsey    schedule 22.07.2009

Твистер Мерсенна

Немного из Википедии:

  • Он был разработан с периодом 2 19937 - 1 (это свойство доказали создатели алгоритма). На практике нет особых причин использовать больший период, так как большинству приложений не требуется 2 19937 уникальных комбинаций (2 19937 примерно 4,3 × 10 6001 < / sup>; это на много порядков больше, чем предполагаемое количество частиц в наблюдаемой Вселенной, которое составляет 10 80).
  • Он имеет очень высокий порядок размерного равнораспределения (см. Линейный конгруэнтный генератор). Это означает, что существует незначительная последовательная корреляция между последовательными значениями в выходной последовательности.
  • Он проходит многочисленные тесты на статистическую случайность, в том числе тесты Дихарда. Он проходит большинство, но не все, даже более строгие тесты на случайность TestU01 Crush.

  • исходный код для многих языков доступен по ссылке.

person Liran Orevi    schedule 22.07.2009

Я бы взял один из библиотеки GNU C, исходный код доступен для просмотра в Интернете.

http://qa.coreboot.org/docs/libpayload/rand_8c-source.html

Но если вас вообще беспокоит качество случайных чисел, вам, вероятно, следует взглянуть на более тщательно написанные математически библиотеки. Это серьезная тема, и стандартные rand реализации не особо задумываются экспертами.

Вот еще одна возможность: http://www.boost.org/doc/libs/1_39_0/libs/random/index.html

(Если вы обнаружите, что у вас слишком много вариантов, вы всегда можете выбрать один наугад.)

person Daniel Earwicker    schedule 22.07.2009
comment
Ссылка rand.c на исходный код кажется неработающей. Попробуйте репозиторий git для _ 2_ и _ 3_ - person Craig McQueen; 14.02.2011
comment
Имейте в виду, что код будет под лицензией GPL или LGPL. Всегда знайте лицензию ваших источников. - person davenpcj; 18.04.2013

Я нашел это: Генерация простых случайных чисел, автор: Джон Д. Готовьте.

Это должно быть легко адаптироваться к C, учитывая, что это всего несколько строк кода.

Изменить: и вы могли бы пояснить, что вы подразумеваете под «относительно высоким качеством». Вы генерируете ключи шифрования для ядерных кодов запуска или случайные числа для игры в покер?

person erjiang    schedule 22.07.2009
comment
Это Джон Д. Кук, который написал этот другой ответ, и он основан на Marsaglia сообщение, на которое он ссылается в своем ответе. - person Craig McQueen; 25.01.2011

Еще лучше использовать несколько регистров сдвига с линейной обратной связью, объединяя их вместе.

Предполагая, что sizeof(unsigned) == 4:

unsigned t1 = 0, t2 = 0;

unsigned random()
{
    unsigned b;

    b = t1 ^ (t1 >> 2) ^ (t1 >> 6) ^ (t1 >> 7);
    t1 = (t1 >> 1) | (~b << 31);

    b = (t2 << 1) ^ (t2 << 2) ^ (t1 << 3) ^ (t2 << 4);
    t2 = (t2 << 1) | (~b >> 31);

    return t1 ^ t2;
}
person BenW    schedule 31.07.2012

Стандартное решение - использовать регистр сдвига с линейной обратной связью.

person tetromino    schedule 22.07.2009

Существует один простой ГСЧ с именем KISS, это один генератор случайных чисел в соответствии с тремя числами.

/* Implementation of a 32-bit KISS generator which uses no multiply instructions */ 

static unsigned int x=123456789,y=234567891,z=345678912,w=456789123,c=0; 

unsigned int JKISS32() { 
    int t; 

    y ^= (y<<5); y ^= (y>>7); y ^= (y<<22); 

    t = z+w+c; z = w; c = t < 0; w = t&2147483647; 

    x += 1411392427; 

    return x + y + w; 
}

Также существует один веб-сайт для тестирования ГСЧ http://www.phy.duke.edu/~rgb/General/dieharder.php.

person zangw    schedule 08.07.2014