2

First-time poster here...

I have the following code to randomize note values and store them in an array loop1[i], where i is a specific step in the loop:

nextNote = random(-2, 3);
note = note + nextNote;

loop1[i] = note;

while (loop1[i] == loop1[i - 1] ||
       loop1[i] == loop1[i - 2] ||
       note > 6 ||
       note < 0) {
  nextNote = random(-2, 3);
  note = note + nextNote;
  loop1[i] = note;
}

(I hope this is clear enough).

Now, it usually works to a certain point until the sketch loops forever in order to randomize an allowed number. Therefore, my questions are:

Running an ATmega 2560, is this actually a task too demanding for the processor or should I suspect that it's not working properly?

How can I optimize the code, but retain the conditions above in order to avoid the loop getting stuck?

  • if note is bigger that 6 before the while, and your random value for nextNote has a higher chance of being positive rather than negative, the most likely scenario is that note will gradually keep increasing, and increasing, and increasing. So your while loop will get "stuck" gradually increasing note, and not doing anything else. Are you sure you don't mean note>0 and note<6 to limit the note values to between -1 and 9. – Gerben Jan 1 '18 at 16:49
  • Thanks for your reply. Short answer to your last question: my intention was to limit the number range from 0 to 6. I fixed that using constrain(). – Erik Jan 1 '18 at 17:00
  • Well, constrain isn't used inside this while loop, so it will still give the problem I described above. I think you'd need something like if(note>6)nextNote=random(-2,-1);else nextNote=random(1,3); in order to ensure it goes back into range again. That should fix the "infinite-loop" problem you are now having. – Gerben Jan 1 '18 at 17:03
  • Now i understand what you're getting at. I've rewritten the code to make it entirely conditional instead of re-randomize prohibited values. Appreciate the input. – Erik Jan 1 '18 at 19:53
2

I think you have a problem with your math here, not with your code. What you are simulating is very similar to a 1-dimensional random walk. According to the linked MathWorld page, for such a process “the most probable number of sign changes in a walk is 0”.

If, at some point in your program, the loop starts with note == 6, and then it starts randomly going up, there is a sizable probability for it to never go back to values below 7.


Edit: One possible solution could be to avoid the random-walk notion and instead repeat the random choice always from the same starting point.

int oldNote = note;  // starting point
do
    note = oldNote + random(-2, 3);
while (
    note == loop1[i - 1] ||       
    note == loop1[i - 2] ||       
    note > 6 ||                       
    note < 0);
loop1[i] = note;
  • Yes, i think you have a point. Earlier i used a model for statistically distributing the probability, in order to restrain the randomization within range. It became a bit overdone, so i was aiming for an easier solution. Now i have new problems, haha... Care to elaborate on a solution? Math is definitely not one of my strengths. – Erik Jan 1 '18 at 17:47
  • @Erik: I edited the answer with a suggested solution. Not the most effective, by far, but close enough to the code you posted. – Edgar Bonet Jan 1 '18 at 23:08
1

Some reasons why it will not work:

  • My feeling is that i gets too big, i.e. it is higher than the length of the array you are using. That can cause crashes, or at least unpredicted results. You can easily check this by printing the value of i (and check against the maximum value).

  • I don't see problems with the while loop (although I would use brackets around note > 6 and around note < 0, but I don't think this is really needed.

  • If the value gets below 0 or higher than 6, still random values are added, assume the value is +10... then it might take a lot of time (if ever) for that value to reach max 6 again. The same is true for values < 0. Maybe you should never allow values of less than 0 and higher than 6 anyway, or making the random values in such a way they tend to go towards the average (3).

Tip to debug:

However, the easiest way to debug this is to print all relevant variables (e.g. nextNote, note, i, the last two notes loop[i-2], loop[i-1] and the current note loop[i]... Also print a line inside the while loop so you know when you skip it or not. This probably will give you enough information to see what is wrong.

  • Thanks for your quick feedback, i should probably have included the code for the entire for-loop as it loops OK. However, i did a bit of optimization using constraint() and do/while conditions instead. – Erik Jan 1 '18 at 16:22
0

The line loop1[i] = note doesn't belong in the loop (or above it); you're not changing i in the loop, so you're just rewriting the same location over and over again.

As for the loop itself, what sort of use case do you have for this, and what sort of distribution do you want? Waiting until it's between 0 and 6 is horribly inefficient. You need to decide what sort of distribution you want and implement it more directly. For instance, you could have a piecewise quadratic distribution by getting a random number between zero and sqrt(3), then squaring the result, and then randomly choosing whether to subtract the result from 6.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.