Problem with LOOP statement

I want to create an array of comma separated whole numbers from 6 to 99. The following code works except that the number 37 is repeated.

let Z=""
let n=6  //first number of the array
loop
    Z=Z+","+n
    n=n+1
    stoploopif n=100
endloop
Z=Z[2,-1]  // gets rid of the leading comma

The problem section of the array looks like “…35,36,37,37,38,39…”

If I change n to 7, 38 is repeated. If n is 8, 40 is repeated.

Can anyone explain this?

It looks like a bug. 69 is also repeated in my test. Item of note, 37 and 69 are the 32nd and 64th numbers.

This code worked for me.

let Z=rep(",", 93)
Z = arrayfilter(Z, ",", "seq()+5")

A For loop also works.

let Z=""
for n, 6, 99
    Z = Z + "," + n
endloop
Z=Z[2,-1]  // gets rid of the leading comma

Thank you. I need to add the for loop to my arsenal.

Or, more elegantly but probably fractionally slower:

let Z=""
for n, 6, 99
    Z = yoke(Z, ",", n)
endloop
1 Like

I’ll bet it isn’t slower.

I usually use the sandwich( function for this but yoke( is cleaner I think :slight_smile:

I was assuming that Z = yoke(Z, ",", n) would be slower than Z = Z + "," + n because yoke( involves two comparisons to see whether the first or third arguments are empty. But it hadn’t occurred to me that Z = Z + "," + n involves two string concatenations, and I don’t know how long they would take in comparison.

You’re right: averaging a thousand results to allow for external factors, I find my version to be about 5.5% quicker than Dave’s — but both under 6ms. Increasing the number of items created in the array from 94 to 10,000, my version (with arguably more in the loop but without the extra statement at the end) becomes about 1.7% slower than Dave’s — which is the kind of difference I meant by ‘fractional’!

Following up on the bug report aspect of this thread, it looks like every 32nd time through the loop, the first statement in the loop is executed twice. If I make that statement a NOP, the results are correct.

let Z=""
let n=6  //first number of the array
loop
    nop
    Z=Z+","+n
    n=n+1
    stoploopif n=100
endloop
Z=Z[2,-1]  // gets rid of the leading comma

Interesting. Do you happen to know if this is a bug that can affect any loop with more than 31 repetitions? That would be a serious issue.

This might be related to a previous discussion with loops skipping a number every 32nd time.

Seems strange that this is reverse of what is noted in this thread. The following code skips the 32nd item instead of duplicating it and goes from 31 directly to 33.

let x=0
Loop
    x=x+1
    zlog x
Until x=35

The previous thread mentions both behaviors.

Actually, it’s the same behavior both times. When a number seems to be skipped, it’s because the assignment statement that increments the counter is the first statement in the loop, and it gets implemented twice. When the number appears twice, it’s because the assignment statement that adds to the array is the first statement in the loop, and that gets done twice.

I opened a new database and ran this procedure. I wanted to see if I got errors on loop 32 and 64.

let n=1
let z=""
loop
    z=z+cr()+(Val(n)^1.3)
    console "Working on loop number "+n
    n=n+1    
until 70

displaydata z

It ran without skipping any steps.

If you change until 70 to until n = 70, then 32^1.3, and 64^1.3 appear twice each in the displaydata. 32^1.3 is 90.5096679918781, and 64^1.3 is 222.860944203808.

So the problem seems to occur when exiting the loop depends on a true or false condition.

I found that the 32 error occurs mostly when the LOOP or FOR items are around complicated procedures. I found in these cases using a GOTO works.

let n=0

StartHere:
n=n+1
bunch of stuff
if n<SomeValue goto StartHere endif

Not very elegant, but avoids the internal counter, which apparently has a bug.

I think you have that backwards. There have been no problems reported with For loops, and when Tom used Until 70 as his end condition, he didn’t have a problem either. The examples that have had problems have had stoploopif or until statements with a comparison operation as the end condition. Those that used internal counters had no problem.

The procedure that started this thread had only 3 statements within the loop. I wouldn’t call that complicated.

If you are actually concerned about performance Dave’s arrayfilter solution is probably at least an order of magnitude faster, maybe more than one order of magnitude.

This seems like it may well be a useful clue in debugging this problem.