рандомный Random(min, max)

BoBo4kA
Offline
Зарегистрирован: 15.01.2016

Захотелось мне рамдомных значений килобайт так на несколько. Казалось бы, в чем проблема то, есть же замечательная функция random(min, max) бери да пользуй, да не тут то было...

Как я в дальнейшем выяснил, последовательность генерируемых значений строго одинаковая при запуске устройста. Её конечно можно изменить указанием параметра randomSeed(seed), но она будет так же одинакова, при одинаковом значении seed. Само значение, в примерах, берут с аналогово входа, который имеет всего то 1024 варианта, что сильно ограничивает кол-во комбинаций. Можно конечно указать и большее значение, как пишут, seed относится к типу long, но опять же, его нужно где то взять, а мне нужно разное значение на разных мк. Так же я выяснил, что время работы мк (если его не передавать в seed конечно) никак не влияет на последовательность генерируемых чисел. Первый вызов (с вкл мк) random() всегда возвращает одинаковое значение, вне зависимости от того, в сетапе вы генерите число или с задержкой в несколько часов...

В итоге сделал для себя функцию, может кому будет интересно или может предложит свой вариат рандомного рандома )

void setup()
{
  analogReference(INTERNAL);
  pinMode(A0, INPUT);
}


byte RND()
{
  byte rndC = 0;
  int rndA = 0;
  int rndB = 0;
  for (byte rndI = 0; rndI < 8; rndI++)
  {
rndNG:
    rndA = analogRead(A0);
    rndB = analogRead(A0);
    if (rndA == rndB)
    {
      goto rndNG;
    }
    rndC = rndC << 1;
    if (rndA < rndB)
    {
      bitSet(rndC, 0);
    }
  }
  return rndC;
}

у моего варианта количество повторов значений заметно неравномерно, в отличии от random(), 0х00 0хFF встречается заметно реже, чем 0хАА и 0х55, но это ожидаемо. У random() кол-во повторов более равномерно. Наверно можно генерить таким образом значение для seed, но я неуверен в получении действительно разных вариантов, а проверять лениво ))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Простите, какое у Вас образование?

Если Вы школьник не старше 8 класса, то, молодец, конечно.

Если же Вы, не дай Бог, имеете высшее техническое образование, то простите, но комментировать такое вопиющее невежество без мата трудно. Читайте Кнута (т.2, гл. 3)! И пока не прочитаете, не возвращайтесь. А со своего ВУЗа потребуйте "взад" деньги за обучение.

Всему же должен быть предел, и невежеству тоже!

BoBo4kA
Offline
Зарегистрирован: 15.01.2016

ПТУ был давно и кроме как втыкать в платы детальки и паять их, там ничему не учили ) Высшее есть, но не техническое...

За рекомендацию почитать, спасибо, но хотелось бы узнать название книги, т.к. на все работы данного автора времени в данный момент нет.

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

BoBo4kA пишет:

хотелось бы узнать название книги, т.к. на все работы данного автора времени в данный момент нет.

Вот, смотрите, Вы выкладываете некую программную разработку для пользования другими людьми, т.е. выступаете в роли программиста. И при при этом спрашиваете название книги Кнута в том контексте, в котором она была упомянута. Это точно то же самое, как если бы Вы написали научный труд по истории 20 века и при этом вдруг спросили бы кто такой Гитлер. Или написали бы теологический труд, а потом бы поинтересовались как называется священное писание христиан.

В русском издании книга называется "Искусство программирования". В первых изданиях называлась "Искусство программирования для ЭВМ".

BoBo4kA
Offline
Зарегистрирован: 15.01.2016

Ознакомился я с 3й главой 2го тома. Читал пропуская кучу формул и заданий. Из прочитаного пришел к выводу, что в любом случае нужно некое стартовое число и некий алгоритм подсчета, от чего я как раз и хочу избавиться.

Возможно не совсем понятно я изложил суть моей проблемы, решением которой как раз и есть код выше.

Мне не нужен крутой алгоритм рандома, мне нужны разные значения при генерации, чего не дает встроенный функционал.

для понимания сути проблемы:

int z = 0;

void setup()
{
  Serial.begin(115200);
}

void loop()
{

}

void serialEvent()
{
  Serial.read();
  for (int j = 0; j < 32; j++)
  {
     z = random(0, 10);
     Serial.print(z);
  }
  Serial.println();
}

запускаю, отправляю любой символ, для срабатывания функции и рандомизации времени старта, делаю еще 2 раза, получаю:

79380248390522737902399703986576
27039991723655814713848046032694
13788381535436595491755418835226
 

далее отключаю устройство, включаю, генерю 3 числа и получаю полностью идентичный вывод.

и не удивлюсь, если у Вас (на 328р) будет идентичный набор цифр, который написал я.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Блин. Самым "точным случайным внешним устройством с точки Ардуны" есть человек. Заставьте его один раз нажать на кнопку и у вас получится исходное число для генератора псевдослучайных чисел. 

BoBo4kA
Offline
Зарегистрирован: 15.01.2016

кнопка да, но и тут вариативность не большая, если кнопка привязана к millis, и нажимается в ограниченном времени от старта. Можно конечно собирать со всех незадействованых аналоговых входов long число в seed.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Вот опять вы придумываете сферического коня в вакууме ,и ищете у него недостатки. У человека точность +- 0,1 секунда в лучшем случае. micros() http://arduino.ru/Reference/Micros  + - 4/1000000 секунды .  Вам что такой разброс мал? 

BoBo4kA
Offline
Зарегистрирован: 15.01.2016

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

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Если у вас пароноя, это не значит, что за вами не следят. Записывайте промежуточные значения в EEPROM  и при рестарте их считавайте, а потом или вставляйте в первичный рандом. Решений много, но скорее у вас лишнее время и вы хотите потратить на дурь, уверяя всех особенно себя , что это для развития вашего ума.

Logik
Offline
Зарегистрирован: 05.08.2014

Кстати, сейчас обявлений куча, отличную дурь через инет продают. И параноя пройдет и сомнения отпадут.

 По теме. Обычный сишный рандом не случайный (СЧ), а псевдослучайный (ПСЧ). Всегда дает заведомо предсказуемое число, гугдите про длинную последовательность. Это очень хороше для отладки, очень плохо для криптографии и некоторых других специфических применений и абсолютно по барабану в 99% остальніых случаях. Потому факт неудовлетворенности ПСЧ скорей симптом паранои. Для 1% критичных к качеству ПСЧ предложеный подход (по умному он называется хэш аппаратных событий)  очень не плох. Собирают данные по всему доступному: АЦП, интервалы между нажатиями, отпусканиями, приемом данных и пр. событий. Если диагноз параноя подтвердится - тогда тяжелая артелерия по типу http://arduino.ru/forum/programmirovanie/schetchik-geigera-arduino?page=2#comment-268313 см. п.2 и далее.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

BoBo4kA пишет:

Захотелось мне рамдомных значений килобайт так на несколько. Казалось бы, в чем проблема то, есть же замечательная функция random(min, max) бери да пользуй, да не тут то было...

Как я в дальнейшем выяснил, последовательность генерируемых значений строго одинаковая при запуске устройста. Её конечно можно изменить...

Спасибо, улыбнуло. )))

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

На PC, чтобы задать(посеять) последовательнось, я беру младший байт команды RDTSC. Здесь, наерно, младший байт micros() пададет, после мануального нажатия кнопку, разумеется.

BoBo4kA
Offline
Зарегистрирован: 15.01.2016

DetSimen пишет:

Здесь, наерно, младший байт micros() пададет, после мануального нажатия кнопку, разумеется.

если только на кнопке будет:

randomSeed(millis());
random(min, max);

в ином случае будет одинаковое значение при первом нажатии кнопки.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

а я говорил про micros(), и только младший байт от него, он меняется быстрее всех. 

BoBo4kA
Offline
Зарегистрирован: 15.01.2016

не так важно где брать, важно что брать, и если передавать, то полное значение, т.к. если передавать только младший байт на выходе будет всего 256 вариантов комбинаций

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Доброго всем!

1. Для тех, кто не знает - я математик, поэтому дам действительно квалифицированное заключение.

2. Не понимаю, что на ТС взъелся Евгений.

Поясню:

а.пусть шум на аналоговом входе распределен неизвестным образом, тогда

б. разность двух случайных величин, равных  измерениям шума в различное время - есть случайная величина имеющая симметричное, относительно 0 распределение.

в. следовательно вероятности положительного и отрицательного значений равны 0.5, при отбрасывании случаев равенства.

г. из событий, имеющих вероятность 0.5 легко собрать случайную величину с равномерным распределением. Это делается ИМЕННО так, как сделал ТС - поразрядно. Если сам догадался - молодец! Если модуль величины не степень двойки, то далают просто дихотомией.

--------------------------

Выводы:

1.использовать как генератор может и накладно, но как коллектор энтропии для старового числа - очень даже ничего!

2. Я уже много раз рассказывал тут, что мои сотрудники как-то раз, люди с высшим образованием, НЕ ОТВЕТИЛИ на вопрос о том, что такое логарифм. А недавно человек с дипломом МГУПИ 10 или 12 летней давности, не смог написать формулу корней КВАДРАТНОГО УРАВНЕНИЯ! А Вы, Женя, хотите, чтобы человек прочел и понял т2.гл.3 Кнута. Наивность?

3. И к самому генератору у ТС какие претензии? Немного смешной - да, но ничего не зная, человек на одной интуиции, написал реально равномерно распределенную случайную величину, которую еще и масштабировть можно на сколько угодно разрядов. Ведь дошло до него брать разность а не с 512 сравнивать? Так что, Евгений, в этот раз Вас не понял я.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

wdrakula пишет:

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

как мне напоминает анекдот про грузина который интуитивно догадался какого рода кофе :один кофе и один булка.

BoBo4kA пишет:
не так важно где брать, важно что брать, и если передавать, то полное значение, т.к. если передавать только младший байт на выходе будет всего 256 вариантов комбинаций
 один раз взял 1/256 комбинация . два раза взял и перемножил  1/256 * 1/256 = 1 /(256*256).  Шаман однако.

китайцы умудрялись из бросания монет - чет и нечет развить гадательную систему. A вам надо комьютер.Ардуина не подходит. http://happy-year.narod.ru/gadaniya/kniga/

BoBo4kA
Offline
Зарегистрирован: 15.01.2016

qwone пишет:

1/256 комбинация . два раза взял и перемножил  1/256 * 1/256 = 1 /(256*256).  Шаман однако.

если брать некую длинную последовательность (на мк), то установка seed обнуляет "счетчик" рандома

для примера, таблица с разным значением seed

int z = 0;
int i = 1;

void setup()
{
  Serial.begin(115200);
}

void loop()
{

}

void serialEvent()
{
  randomSeed(i);
  Serial.read();
  for (int j = 0; j < 32; j++)
  {
    z = random(1, 10);
    Serial.print(z);
  }
  Serial.print("  seed=");
  Serial.println(i);
  i++;
}

/* результат
58635979921979138882721357719883  seed=1
96158847721738145663429483498554  seed=2
44563715529687162434929529196225  seed=3
82986674429446179215638655785986  seed=4
39591442229395196986238782473658  seed=5
77924319928164113757837827172329  seed=6
25438278828923131538546964761181  seed=7
62852146627772147399146199458752  seed=8
19466914427631164171745236157424  seed=9
57889773327489172852355362745185  seed=10
*/

далее, для упрощения, т.к. делаю ручками, сделаю вывод 5 цифр с рандомным seed от 1 до 10

я убрал 0, т.к. это значение меняет seed по своему алгоритму, искать который я не хочу.

int z = 0;
int i = 1;

void setup()
{
  Serial.begin(115200);
}

void loop()
{

}

void serialEvent()
{
  i=random(1,10);
  randomSeed(i);
  Serial.read();
  for (int j = 0; j < 5; j++)
  {
    z = random(1, 10);
    Serial.print(z);
  }
  //Serial.print("  seed=");
  //Serial.println(i);
  Serial.println();
}

/* результат
39591
82986
77924
44563
25438
96158
62852
58635
19466
19466
19466
*/

По коду, мы "рандомим" i, т.к. это первый раз, это значение можно найти в таблице выше при seed=1, это значение 5, смотрим ряд при seed=5, нас интересуют первые 5 символов, это 39591, 6й знак в этом ряде это 4, это значение примет i при 2м заходе в функцию, следующие 5 символов ряда при seed=4 - 82986, ну и так далее... что забавно, ряд при seed=9 возвращает 9 и такой рандом начинает возвращять цикличные значения.

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

Можно конечно было сюда вставить и

  int val = analogRead(0);
  val = map(val, 0, 1023, 1, 9);
  randomSeed(val);

и разобрать всю цепочку, но уже не сегодня )

toc
Offline
Зарегистрирован: 09.02.2013

простой способ
https://xkcd.com/221/

toc
Offline
Зарегистрирован: 09.02.2013

а ещё в ардуине в качестве начального числа можно использовать
- показание встроенного в чип вольтметра
- показание встроенного в чип термометра

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

wdrakula пишет:

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

Боюсь, что Вы были недостаточно внимательны к коду - прросто не вникли в то, что реально написано, "реальной равномерностью" там и не пахнет.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Евгений. Я пояснил все в своем комменте. Типовое поразрядное бинарное построение. Ну да Б.. г с Вами. Может я чего и не понял.

Logik
Offline
Зарегистрирован: 05.08.2014

wdrakula пишет:

а.пусть шум на аналоговом входе распределен неизвестным образом, тогда

Пусть, я не возражаю. Но в реале он очень даже известный  - основная составляющая 50Гц, наводится понятно откуда и очень сильно несинусоидальная. Дето 3/4 периода - почти 0 +слабый шум, а остальное выбросы острые +сильный шум. Потому с АЦП, как есть, использовать базой генератора не годится. Только как часть для хеша.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Эксперимент на Леонарде, она у меня для всех тестов, показал, что распроеделение разности двух последовательных измерений на неподключенном аналоговом входе ведет себя непредсказуемо. Сильно зависит от паузы между измерениями.

 - наилучший результат 49.5% и 50.5% - измерения без паузы с референсом по питанию.

 - референс внутренний, без паузы = 48 и 52 (как у ТС изначально);

 - разные ноги , пауза delay(1) необходима, 30 и 70 и хуже!

После использования АЦП любым способом распределение непредсказуемо искажается.

------------------------

Вывод по практическому эксперименту:

Идею ТС можно использовать, но не в постоянной работе, а для сбора энтропии для "повева". Посев нужно производить при старте устройства.

Большая равномерность достигается при использовании референса по умолчанию (питание).