Функция random()

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

Евгений Петрович!

Счастья, любви, удачи, здоровья, бодрости, хорошего настроения!

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

strarbit, т.к. не дождался Вашего варианта, размещаю свой. Если посчитаете, что я что-то не то написал, поправьте:

#define arraySize (6*128)
int currSize = 6;

int bArray[arraySize];

void swap(int & a, int & b) {
  int tmp = a;
  a = b;
  b = tmp;
}

void printArray() {
  for (int i = 0; i < ((currSize < 25) ? currSize : 25); i++) {
    Serial.print(bArray[i]);
    Serial.print(' ');
  }
  Serial.print('\n');
}

long fill()
{
  Serial.print(F("   Array length: "));
  Serial.println(currSize);
//  Serial.println(F("zapolnyaete massiv posledovtelnimi chislami"));
  long t0 = millis();
  for (int i = 0; i < currSize; i++) {
    bArray[i] = i + 1;
  }
  long t1 = millis();
//  printArray();
  Serial.print(F("random: "));
  long t2 = millis();
  for (int i = 0; i < currSize; i++)
  {
    swap(bArray[i], bArray[random(currSize)]);
  }
  long t3 = millis();
  printArray();
  return t1-t0 + t3-t2;
}

bool check(int c, int n) {
  for (int i = 0; i < c; i++) {
    if (bArray[i] == n) return true;
  }
  return false;
}

long fill2()
{
  Serial.print(F("terrible: "));
  long t0 = millis();
  bArray[0] = random(currSize)+1;
  for (int i = 1; i < currSize; i++) {
    int tmp = random(currSize)+1;
    while (check(i,tmp)) { tmp = random(currSize)+1; }
    bArray[i] = tmp;
  }
  long t1 = millis();
  printArray();
  return t1-t0;
}

void setup()
{
  Serial.begin(115200);
  for (byte i = 0; i < 8; ++i) {
    long time1 = fill();
//    Serial.print(F("   Elapsed time: "));
//    Serial.println(time1);
    long time2 = fill2();
    Serial.print(F("   Elapsed time, random: "));
    Serial.print(time1);
    Serial.print(F(", terrible: "));
    Serial.println(time2);
    Serial.println("");
    currSize *= 2;
  }
}

void loop()
{

}

Результат (сравните время выполнения):

   Array length: 6
random: 2 1 3 6 5 4 
terrible: 1 3 6 2 4 5 
   Elapsed time, random: 1, terrible: 1

   Array length: 12
random: 5 12 4 8 1 6 9 11 7 2 10 3 
terrible: 3 9 8 10 2 4 1 6 7 5 11 12 
   Elapsed time, random: 2, terrible: 5

   Array length: 24
random: 5 18 6 9 20 8 14 22 12 11 17 15 7 19 3 2 21 1 4 23 10 24 16 13 
terrible: 10 24 21 18 15 2 22 7 1 16 4 3 23 8 9 13 14 19 17 20 11 5 6 12 
   Elapsed time, random: 2, terrible: 11

   Array length: 48
random: 19 36 5 47 13 45 3 23 4 18 30 37 31 28 29 8 10 42 12 25 26 7 1 6 21 
terrible: 21 5 34 28 37 39 25 30 4 36 47 12 8 42 26 23 10 22 9 33 45 15 31 41 11 
   Elapsed time, random: 6, terrible: 21

   Array length: 96
random: 94 47 18 93 6 40 54 15 65 13 28 85 11 27 29 37 60 58 30 55 53 21 20 44 56 
terrible: 41 10 24 95 17 18 70 38 1 40 50 42 52 57 6 65 72 94 93 47 73 59 28 9 89 
   Elapsed time, random: 11, terrible: 69

   Array length: 192
random: 43 56 31 49 59 97 108 83 167 46 121 35 117 128 23 156 36 62 27 132 24 138 135 110 143 
terrible: 93 78 187 67 139 81 166 131 14 113 44 28 188 98 137 105 51 82 124 95 117 34 175 63 48 
   Elapsed time, random: 20, terrible: 140

   Array length: 384
random: 65 211 145 310 28 101 369 350 100 144 122 271 354 159 69 79 305 314 78 302 257 295 71 35 60 
terrible: 311 148 152 352 280 337 328 133 266 19 107 366 247 157 56 190 322 95 61 96 384 234 286 177 115 
   Elapsed time, random: 38, terrible: 460

   Array length: 768
random: 65 358 159 674 569 74 99 68 217 131 237 361 447 144 529 147 318 729 64 232 568 257 220 83 598 
terrible: 531 188 146 178 430 419 725 761 16 628 575 248 262 73 81 106 162 536 481 666 388 184 417 440 755 
   Elapsed time, random: 76, terrible: 2162

 

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

DIYMan, посыпаю голову пеплом, по поводу двух ошибок я погорячился. Кстати, у меня в процитированной тобой строке ошибки тоже нет.

Итого, остается одна:

void swap1(byte & a, byte & b) {
  byte tmp = a;
  a = b;
  b = tmp;
}

void swap2( byte &x, byte &y)
{
  x ^= y;
  y ^= x;
  x ^= y;
}

void setup() {
  // put your setup code here, to run once:
  byte a = 5;
  Serial.begin(115200);
  Serial.println(a);
  swap1(a,a);
  Serial.println(a);
  swap2(a,a);
  Serial.println(a);
}

void loop() {
  // put your main code here, to run repeatedly:

}

Вывод:

5
5
0

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

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

andriano пишет:

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

Свап ксором - дремучая фича. Только ты немного лукавишь - ты "обмениваешь" ОДНУ переменную ;) Вот код:

// Example program
#include <iostream>
#include <string>

void swap2( uint8_t &x, uint8_t &y)
{
  x ^= y;
  y ^= x;
  x ^= y;
}


int main()
{
  uint8_t b1 = 5;
  uint8_t b2 = 6;
  std::cout << "Before: "  << int(b1) << "-" << int(b2) << "\n";
  swap2(b1,b2);
  std::cout << "After: "  << int(b1) << "-" << int(b2) << "\n";
}

Запускал здесь: http://cpp.sh/ - результат: обменивается, как надо. Подчёркиваю - это обмен ДВУХ переменных, а не одной, как в продемонстрированном тобой примере. Ибо если сделать так:

// Example program
#include <iostream>
#include <string>

void swap2( uint8_t &x, uint8_t &y)
{
  x ^= y;
  y ^= x;
  x ^= y;
}


int main()
{
  uint8_t b1 = 5;
  std::cout << "Before: "  << int(b1) << "-" << int(b1) << "\n";
  swap2(b1,b1);
  std::cout << "After: "  << int(b1) << "-" << int(b1) << "\n";
}

То вывод будет другой, как у тебя. Нельзя применять микроскоп для забивания гвоздей - если сказано, что эта функция для обмена значениями двух переменных - то она для обмена значениями двух переменных, а то, что ты сделал - это вырожденный и, заметь, полностью бессмысленный случай - зачем менять что-то в одной переменной, если она и так уже имеет значение? Т.е. ты делаешь бессмыслицу, согласись ;)

Обмен методом XOR, кстати, был актуален, когда вычислительных ресурсов было очень мало, и экономили даже один байт. Сейчас, конечно, проще забить, и поюзать более мнемонически понятный вариант с промежуточной переменной. Однако и тут замечу: метод с XOR в хитрых случаях будет сильно выгодней одного байта на стеке, т.к. в случае типа данных размерностью, скажем, 100 байт - в твоём случае на стеке будут лишние 100 байт, в моём - не будут. Для такого типа данных в твоём случае потребуется реализация оператора присваивания, в моём - арифметического оператора, но по итогу - вариант с XOR выигрывает по размеру стека у варианта с промежуточной переменной, всегда.

Вот пример шаблонной функции swap:

// Example program
#include <iostream>
#include <string>

template<class T>
void swap2( T &x, T &y)
{
  x ^= y;
  y ^= x;
  x ^= y;
}


int main()
{
  uint64_t b1 = 5;
  uint64_t b2 = 6;
  std::cout << "Before: "  << int(b1) << "-" << int(b2) << "\n";
  swap2(b1,b2);
  std::cout << "After: "  << int(b1) << "-" << int(b2) << "\n";
}

Как видишь - там вообще любой тип данных может быть, к которому можно применить операторы ^ и =. В показанном выше примере в твоём случае на стеке будет уже лишних 8 байт. А теперь представь, что стек у тебя размером, скажем, байт в 16 - как считаешь, много это - 8 байт от стека в 16 байт, или нет? ;)

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

DIYMan пишет:

То вывод будет другой, как у тебя. Нельзя применять микроскоп для забивания гвоздей - если сказано, что эта функция для обмена значениями двух переменных - то она для обмена значениями двух переменных, а то, что ты сделал - это вырожденный и, заметь, полностью бессмысленный случай - зачем менять что-то в одной переменной, если она и так уже имеет значение? Т.е. ты делаешь бессмыслицу, согласись ;)

Давай вернемся к началу.

Для решения вполен конкретной задачи, сформулированной ТС, был предложен конкретный алгоритм, предполагающий тупой обмен в цикле одного элемента массива на ЛЮБОЙ другой. В т.ч. и на самого себя.

ТС не понял, что я подразумевал под именем swap в УКАЗАННОМ алгоритме, и я пояснил это примером. 

После этого ты предложил СВОЮ замену реализацию функции swap, которая для данного алгоритма НЕ ПОДХОДИТ.

Т.е. ты своим советом превратил работающий алгоритм в неработающий.

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

 

PS. И - да, если менять переменную бессмысленно (вне зависимости от того, по какой причине), то это совершенно не значит, что ее можно ПОРТИТЬ.

PPS. Опять же, я придерживаюсь мнения, что правильно написанная функция должна по возможности корректно работать с некорректными данными. Никто ведь не мешал написать, например, так (и байт из стека не расходуется):

void swap( byte &x, byte &y)
{
  if(&x != &y) {
    x ^= y;
    y ^= x;
    x ^= y;
  }
}

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

andriano пишет:

Для решения вполен конкретной задачи, сформулированной ТС, был предложен конкретный алгоритм, предполагающий тупой обмен в цикле одного элемента массива на ЛЮБОЙ другой. В т.ч. и на самого себя.

Ок, принимается. Решается простой проверкой. Я не настаиваю на применении варианта с XOR, если ты заметил. Пусть юзает любой вариант, какой хочет. Свои мысли я высказал выше, про вольное обращение со стеком ты так ничего и не прокомментировал. Впрочем, и не стоит - я уже заметил, что тут проще привязаться к какому-нибудь несущественному моменту (ах, ну да, Дима должен за всех всё сразу писать, в том числе контроль всех возможных нюансов - именно для этого нужен форум), вместо того, чтобы уделить внимание конкретике. Ты пока - занимаешься первым, т.е. тупо мелешь воду в решете.

Вариант с XOR рабочий? Рабочий. До@баться и до столба можно, это очевидно. Умный - увидит, исходя уже из самой реализации XOR-swap, что там требуется ДВА разных адреса, и добавить махонькую проверочку, конечно, если ему хочется стек поэкономить, и юзать XOR-swap. Опять же - проверка нужна не везде, и впиху@вывать её прямо внутрь реализации swap - оверхед и признак херового программера, такое моё мнение: всё должно быть по-максимуму эффективно, и если внутри swap не нужна проверка - я её там и не писал. В некоторых, подчеркну, в НЕКОТОРЫХ случаях такая проверка нужна, случай ТС - тот самый. Но и в этом случае её не стоит по соображениям архитектуры пихать внутрь реализации - такое моё мнение номер два. Программист должен читать доку к API - это раз. Уметь читать код и понимать его особенности - это два. И не быть бездумной собачкой, считающей, что за него всё-всё делают - это три.

Зануда же - будет до@бываться до деталей, на которые мне, честно говоря, наплевать - я тут сопли за неумехами подтирать не намерен: не разбираются - this is Sparta!, следующий.

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

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

DIYMan пишет:

Вариант с XOR рабочий? Рабочий.

Рабочий - это когда работает всегда. А когда иногда - это не совсем рабочий.

Цитата:

Зануда же - будет до@бываться до деталей, на которые...

Вот именно. 

В теме был сформулирован вопрос. На него дан ответ.

Тут ты вылез со своим "уточнением", причем в данном случае - неверным. Никто ничего не сказал.

Потом ты разместил псевдокод. Без проверки, без компиляции. Имеешь полное право. Я тоже, когда размещаю псевдокод, не пытаюсь его компилировать. Опять никто ничего не сказал.

Посетительница форума попыталась из твоего псевдокода сделать скетч. При этом не заметила твоих "неточностей" и насажала своих ошибок. Имеет полное право.

Я исправил код, упомянув про ошибки. Не называя имен. И тут ты взвился. Зачем? Это и есть твоя позиция?

bwn
Offline
Зарегистрирован: 25.08.2014

ЕвгенийП пишет:

Неочевидное можно, мне и самому интересно сделать,  но только завтра, у меня ДР сегодня, пора к пьянке готовиться. 

Ню, хоть и поздно заглянул, присоединяюсь к тостующим.))))

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

Странный ты какой-то, Андриано! ;)

Ты ж, вроде(?), говорил, что изучал программирование? Правда на Паскале, но это не страшно, моим первым языком тоже был Паскаль и ничего... ;). Тривиальные то задачки вроде должен знать? Или нет?

Так, по делу: своп без промежуточной переменной - это же разминочные олимпиадные задачки по программированию:

x = x + y; y = x - y; x = x - y;

или

x = x - y; y = x + y; x = y - x;

или XOR

x = x ^ y; y = x ^ y; x = x ^ y;

последнее решение всегда ценилось именно за красоту и отсутствие переполнений.

В С это оформляли макросом, который точно так же даст 0, если скормить ему одно имя два раза и чО?

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

wdrakula пишет:

или XOR

x = x ^ y; y = x ^ y; x = x ^ y;

последнее решение всегда ценилось именно за красоту и отсутствие переполнений.

а я первый сказал, что красиво )))

BigMeister
Offline
Зарегистрирован: 11.02.2018

У меня второстепенный вопрос, почему не получается выводить в com-порт текст вместе с случайным числом ?

int randNum;
void setup() 
{
  Serial.begin(9600);
  randomSeed(analogRead(0));
}

void loop() 
{
  randNum = random(1, 10);
  Serial.println("Number is" + randNum);
  delay(200);
}

В выводе видны только обрывки текста.

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

Потому, что выводить можно только одно значение.

Или сначал сделайте строку в которой есть всё, что надо и её выводите, или выводите несколькими print'ами. Ну или возьмите б-ку Printing (я тут где-то выкладывал на форуме), а там хоть потоком печатайте, хоть printf'ом

BigMeister
Offline
Зарегистрирован: 11.02.2018

ЕвгенийП пишет:

Потому, что выводить можно только одно значение.

Или сначал сделайте строку в которой есть всё, что надо и её выводите, или выводите несколькими print'ами. Ну или возьмите б-ку Printing (я тут где-то выкладывал на форуме), а там хоть потоком печатайте, хоть printf'ом

Спасибо, сделал так

int randNum;
String text = "Number is ";
void setup() 
{
  Serial.begin(9600);
  randomSeed(analogRead(0));
}

void loop() 
{
  randNum = random(1, 10);
  Serial.println(text + randNum);
  delay(200);
}

 

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

Ну, работать должно, но ради воробья расчехлять такую пушку, как String. Ладно, когда с памятью припрёт - переделаете.