News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

Calculations in For Next loops for the "Next" part

Started by RGV250, May 24, 2021, 08:26 PM

Previous topic - Next topic

RGV250

I am converting an Arduino program and have come across this, it looks like the "Next" values are calculated inline. I do not think Positron will allow this so I am wondering if it would be best to try to do them after the PaintSetPixel line or try something like While/Wend.
void Paint_DrawPoint( UWORD Xpoint, UWORD Ypoint, UWORD Color, DOT_PIXEL Dot_Pixel,DOT_STYLE Dot_FillWay)
{
    if (Xpoint > Paint.Width || Ypoint > Paint.Height) {
        Debug("Paint_DrawPoint Input exceeds the normal display range\r\n");
        return;
    }

    int16_t XDir_Num , YDir_Num;
    if (Dot_FillWay == DOT_FILL_AROUND) {
        for (XDir_Num = 0; XDir_Num < 2*Dot_Pixel - 1; XDir_Num++) {
            for (YDir_Num = 0; YDir_Num < 2 * Dot_Pixel - 1; YDir_Num++) {
                if(Xpoint + XDir_Num - Dot_Pixel < 0 || Ypoint + YDir_Num - Dot_Pixel < 0)
                    break;
                // printf("x = %d, y = %d\r\n", Xpoint + XDir_Num - Dot_Pixel, Ypoint + YDir_Num - Dot_Pixel);
                Paint_SetPixel(Xpoint + XDir_Num - Dot_Pixel, Ypoint + YDir_Num - Dot_Pixel, Color);
            }
        }
    } else {
        for (XDir_Num = 0; XDir_Num <  Dot_Pixel; XDir_Num++) {
            for (YDir_Num = 0; YDir_Num <  Dot_Pixel; YDir_Num++) {
                Paint_SetPixel(Xpoint + XDir_Num - 1, Ypoint + YDir_Num - 1, Color);
            }
        }
    }
}

Regards,
Bob

trastikata

#1
I don't think it will work with the For-Next loop. Simple example like:
Dim a As Byte
Dim b As Byte
Dim i As Byte

Main:
    For i = a To b + 20
        b = a + 1
    Next

generates this assembler code

F1_000012 equ $ ; in [TEST.BAS] For I = A To B + 20
    movlw 20
    addwf _B,W,0
    movwf PBL_VAR0,0
    movff _A,_I
_frlb__2
    movf _I,W,0
    subwf PBL_VAR0,W,0
    bnc _nxlb__3
F1_000013 equ $ ; in [TEST.BAS] B = A + 1
    incf _A,W,0
    movwf _B,0
_ctlb__4
F1_000014 equ $ ; in [TEST.BAS] Next
    incf _I,F,0
    bnc _frlb__2
_nxlb__3

The value of the system variable PBL_VAR0 is loaded at the beginning of the For-Next loop and then it loops between _frlb__2 and _nxlb__3 where the value of the system variable PBL_VAR0 is not being updated with the newly calculated value of B.

So I think Repeat { Instructions : } Until Condition is the better option since the end condition is being calculated inside the loop and compared at the end of each iteration.

RGV250

Hi,
Took a few beers and a bit of head scratching but this is what seems to work, still got the If calculations to do.
This is before the For/Next loop,
XDir_NumXX = (2*Dot_Pixel) - 1
YDir_NumYY = (2*Dot_Pixel) - 1    
   If Dot_FillWay = DOT_FILL_AROUND Then
        For XDir_Num = 0 To XDir_NumXX   
            For YDir_Num = 0 To YDir_NumYY 

Also had a lot of grief finding out about Conditional ternery operators, oh the joys of C++

Bob

Stephen Moss

Quote from: trastikata on May 24, 2021, 09:22 PMDim a As Byte
Dim b As Byte
Dim i As Byte

Main:
    For i = a To b + 20
        b = a + 1
    Next
I am not sure if it make a difference to the result but I think that should be For i = a to (B + 20) otherwise it is possible the "+ 20" is not being seen as the compiler takes b as the end value.
Also, I may be wrong as I know some C but am not an expert but I don't think the supplied code is incrementing the values use in the For statement within the loop as it is in your example.

Quote from: RGV250 on May 24, 2021, 08:26 PMint16_t XDir_Num , YDir_Num;
    if (Dot_FillWay == DOT_FILL_AROUND) {
        for (XDir_Num = 0; XDir_Num < 2*Dot_Pixel - 1; XDir_Num++) {
            for (YDir_Num = 0; YDir_Num < 2 * Dot_Pixel - 1; YDir_Num++) {
                if(Xpoint + XDir_Num - Dot_Pixel < 0 || Ypoint + YDir_Num - Dot_Pixel < 0)
                    break;
                // printf("x = %d, y = %d\r\n", Xpoint + XDir_Num - Dot_Pixel, Ypoint + YDir_Num - Dot_Pixel);
                Paint_SetPixel(Xpoint + XDir_Num - Dot_Pixel, Ypoint + YDir_Num - Dot_Pixel, Color);
            }
        }
The For - Next section of the 8-bit manual states...
Endcount is the number on which the loop will finish. This does not have to be an actual number, it could be the contents of another variable, or an expression.

If it can be an expression that suggests it can be calculate it inline. I may be wrong as I have not tried it but I think the equivalent of the above would be something like...Dim XDir_Num as Word
Dim YDir_Num as Word
If Dot_FillWay = Dot_Fill_Around Then
   For XDir_Num = 0 to ((2 * Dot_Pixel)-1)
       For YDir_Num = 0 to ((2 * Dot_Pixel)-1)


RGV250

Hi Stephen,
I did resolve it but not quite as neat as yours, I think I tried that but without the brackets around the -1, I have tried it and it works so I will be using that.
What annoys me is that someone has written this code and it works but there are zero comments so it is a nightmare to convert.

Bob

tumbleweed

Quote from: Stephen Moss on May 25, 2021, 09:20 AMAlso, I may be wrong as I know some C but am not an expert but I don't think the supplied code is incrementing the values use in the For statement within the loop as it is in your example.
...
 I may be wrong as I have not tried it but I think the equivalent of the above would be something like...
Both of those statements are correct. There's nothing wrong with the original For loops, and there's nothing being modified inside the loops.

Since Dot_Pixel isn't modified inside the loop, the C compiler is free to optimize the end condition calculation '2*Dot_Pixel - 1' and only evaluate it once at the beginning.

That makes the C code
for (XDir_Num = 0; XDir_Num < 2*Dot_Pixel - 1; XDir_Num++)and
XDir_NumXX = (2*Dot_Pixel) - 1
For XDir_Num = 0 To XDir_NumXX
almost equivalent (the Basic code will do 1 more iteration than the C version since it's "0 to x" vs "< x").

trastikata

Quote from: Stephen Moss on May 25, 2021, 09:20 AMI am not sure if it make a difference to the result but I think that should be For i = a to (B + 20) otherwise it is possible the "+ 20" is not being seen as the compiler takes b as the end value.

That's why I posted the Assembler code:

F1_000012 equ $ ; in [TEST.BAS] For I = A To B + 20
    movlw 20      --> Load 20
    addwf _B,W,0  --> Add 20 to B
    movwf PBL_VAR0,0 --> Load the result in system variable PBL_VAR0
    movff _A,_I

Quote from: Stephen Moss on May 25, 2021, 09:20 AMIf it can be an expression that suggests it can be calculate it inline.

I think no, it simply suggest that you can use the result of an expression as end count, to verify if it is dynamically updated, let's look at the Assembler again:

_frlb__2
    movf _I,W,0
    subwf PBL_VAR0,W,0   
    bnc _nxlb__3
F1_000013 equ $ ; in [TEST.BAS] B = A + 1
    incf _A,W,0
    movwf _B,0
_ctlb__4
F1_000014 equ $ ; in [TEST.BAS] Next
    incf _I,F,0
    bnc _frlb__2
_nxlb__3

The only time the system variable is touched (subwf PBL_VAR0,W,0 ) when it is compared whether to branch to the exit or to return to the beginning of the loop. And the result from the expression incf _A,W,0 : movwf _B,0 (b = a + 1) doesn't load in the system variable PBL_VAR0.

My understanding of Assembler is crude and my interpretation could be wrong, maybe someone more knowledgeable can advise on it.


tumbleweed

#7
You have it right.

In your example, the end condition 'B+20' is only evaluated at the beginning of the For loop, even though B is changed inside the loop. You wouldn't want to use a For loop here.

Even though it's just an example, in ANY language I think you want to be very careful modifying the end condition of a loop, even if it's allowed.

top204

A C and C++ for loop, is, essentially, a Repeat loop, where the start and end limits to the loop and the amount the loop will increment or decrement are placed within the opening braces. It can also have multiple loops within the same set of braces or an infinite loop. Sometimes, it looks so complex it is hard to decipher what the heck a loop is actually doing, even after using C and C++ for 20-odd years! LOL So the first thing I do when translating code for another language is to untangle the messy C and C++ code written by the "nerds", for no real reason, and make the code, actually, readable by us "non-nerds". :-)

A standard For-Next loop will do the same function as a C for loop, as long as the looping variable is not to be interfered with inside the loop, which is always a bad thing to do. To get the same functionality to a C or C++ for loop that alters the looping limit variables, use the Repeat-Until or Do-Loop Until or While-Wend directives.