Auto decrementing a variable appears to work in HPPL while incrementing doesn't.

Here's a snippet from a C program and an equivalent snippet in HPPL

Notice the assignment statement right in the IF statement.:

Code:

if (!(t=a[x]-a[--y]) || x-y==abs(t)){

y=0;

while(!--a[x])

--x;

}

Code:

IF (NOT(T:=A(X)-A(--Y)) OR X-Y==ABS(T)) THEN

Y:=0;

WHILE NOT --A(X) DO

--X;

END;

END;

It's hard to trace exactly what is happening in the code without knowing the values in list A, but are you sure that it's actually decrementing?

When I use --X in an HPPL program, or on the Home screen, it is interpreted as -(-X), the negative of the negative of X. Likewise, ---X is -(-(-X)).

In CAS programs (with #cas ... #end), or on the CAS screen, it does allow a++ and a-- but not ++a or --a.

I don't know if this is considered a bug, but in CAS a++ is really doing ++a, incrementing BEFORE evaluating the expression. Likewise for a--. Same behavior in xcas. Maybe it's documented somewhere, but I couldn't find it.

(07-03-2022 09:14 AM)Wes Loewer Wrote: [ -> ]It's hard to trace exactly what is happening in the code without knowing the values in list A, but are you sure that it's actually decrementing?

When I use --X in an HPPL program, or on the Home screen, it is interpreted as -(-X), the negative of the negative of X. Likewise, ---X is -(-(-X)).

In CAS programs (with #cas ... #end), or on the CAS screen, it does allow a++ and a-- but not ++a or --a.

I don't know if this is considered a bug, but in CAS a++ is really doing ++a, incrementing BEFORE evaluating the expression. Likewise for a--. Same behavior in xcas. Maybe it's documented somewhere, but I couldn't find it.

When I substitute the -- notation for the original code, the program gives the same answer! If it's not actually doing a decrement, it's an awfully big coincidence that it should still work the same, no?

Original code:

Code:

` `

Y:=Y-1;

T:=A(X)-A(Y);

IF T==0 OR X-Y==ABS(T) THEN

Y:=0;

A(X):=A(X)-1;

WHILE A(X)==0 DO

X:=X-1;

A(X):=A(X)-1;

END;

END;

(07-03-2022 09:14 AM)Wes Loewer Wrote: [ -> ]I don't know if this is considered a bug, but in CAS a++ is really doing ++a, incrementing BEFORE evaluating the expression. Likewise for a--. Same behavior in xcas. Maybe it's documented somewhere, but I couldn't find it.

Not sure I understand what you mean. a++ does this: find a in the table of variables in the current evaluation context, add 1 to this value (in place).

(07-03-2022 11:02 AM)parisse Wrote: [ -> ] (07-03-2022 09:14 AM)Wes Loewer Wrote: [ -> ]I don't know if this is considered a bug, but in CAS a++ is really doing ++a, incrementing BEFORE evaluating the expression. Likewise for a--. Same behavior in xcas. Maybe it's documented somewhere, but I couldn't find it.

Not sure I understand what you mean. a++ does this: find a in the table of variables in the current evaluation context, add 1 to this value (in place).

In other languages,

a++ evaluates

a then increments

a, while

++a increments

a then evaluates

a. For instance, in C and its descendants,

Now

a and

b are both 6. However,

In C,

a is again 6 but

b is 5 since

a is not incremented until

after the right side is evaluated. In CAS,

a and

b are both 6. So

a++ in CAS is like

++a in C.

I don't know if it's worth "fixing", but the behavior should be documented somewhere. There's currently no Help entry for ++ or -- in xcas or Prime. That would be a good place for it.

(07-03-2022 09:38 AM)toml_12953 Wrote: [ -> ]If it's not actually doing a decrement, it's an awfully big coincidence that it should still work the same, no?

You're right that it's an awfully big coincidence, but I can't tell for sure without knowing the starting values of X, Y, T, and A. However, this code

Code:

`EXPORT AAA()`

BEGIN

A:=5;

--A;

RETURN A;

END;

returns 5, not 4. So --A is not decrementing A.

(07-03-2022 09:38 AM)toml_12953 Wrote: [ -> ]If it's not actually doing a decrement, it's an awfully big coincidence that it should still work the same, no?

You've got me really curious. What happens if you just drop the three -- in the original code?

Code:

`IF (NOT(T:=A(X)-A(Y)) OR X-Y==ABS(T)) THEN`

Y:=0;

// This is an infinite loop only if A(X) is false (zero).

// If A(X) is true (not zero), then the loop is not executed at all.

WHILE NOT A(X) DO

X; // does nothing

END;

END;

Does it still produce the same result?

(07-03-2022 01:49 PM)Wes Loewer Wrote: [ -> ] (07-03-2022 09:38 AM)toml_12953 Wrote: [ -> ]If it's not actually doing a decrement, it's an awfully big coincidence that it should still work the same, no?

You've got me really curious. What happens if you just drop the three -- in the original code?

Code:

`IF (NOT(T:=A(X)-A(Y)) OR X-Y==ABS(T)) THEN`

Y:=0;

// This is an infinite loop only if A(X) is false (zero).

// If A(X) is true (not zero), then the loop is not executed at all.

WHILE NOT A(X) DO

X; // does nothing

END;

END;

Does it still produce the same result?

Yes it does! It seems like this code is never executed at all so I could put anything in there and still come up with the right answer (876)

Here's the entire C program:

Code:

main()

{

int x,y,r,s,t,n,a[9];

for(n=1000;n>0;--n){

r=8;

s=0;

x=0;

do{

a[++x]=r;

do{

++s;

y=x;

while(y>1)

if (!(t=a[x]-a[--y]) || x-y==abs(t)){

y=0;

while(!--a[x])

--x;

}

} while(y!=1);

} while(x!=r);

}

printf("%d",s);

}

(07-03-2022 02:18 PM)toml_12953 Wrote: [ -> ]Here's the entire C program:

Code:

main()

{

int x,y,r,s,t,n,a[9];

for(n=1000;n>0;--n){

r=8;

s=0;

x=0;

do{

a[++x]=r;

do{

++s;

y=x;

while(y>1)

if (!(t=a[x]-a[--y]) || x-y==abs(t)){

y=0;

while(!--a[x])

--x;

}

} while(y!=1);

} while(x!=r);

}

printf("%d",s);

}

What an interesting little program. I cannot begin to image what it is trying to calculate. Whatever it is doing, it repeats the exact same calculation 1000 times, and a[0] never gets initialized or used.

Do tell, what is this?

(07-03-2022 01:03 PM)Wes Loewer Wrote: [ -> ] (07-03-2022 11:02 AM)parisse Wrote: [ -> ]Not sure I understand what you mean. a++ does this: find a in the table of variables in the current evaluation context, add 1 to this value (in place).

In other languages, a++ evaluates a then increments a, while ++a increments a then evaluates a. For instance, in C and its descendants,

I think it's bad to increment a variable and simultaneously do an assignation, because it's confusing, I never do that myself, I always do a++ or ++a standalone and that's equivalent. If you want to do both, write 2 instructions, I'm pretty certain it's translated exactly the same way by the compiler and therefore as efficient. That kind of "compact" code is more difficult to read/fix, like oneliners in interpreted languages.

Moreover evaluation is much simpler in a compiled langage like C than in a CAS. Imagine that a evaluate to a symbolic identifier b, what should mean a distinction where we evaluate before incrementing: should b be incremented instead of a?

(07-03-2022 06:24 PM)Wes Loewer Wrote: [ -> ]What an interesting little program. I cannot begin to image what it is trying to calculate. Whatever it is doing, it repeats the exact same calculation 1000 times, and a[0] never gets initialized or used.

Do tell, what is this?

It solve 8-Queen puzzle. (code really need comments!)

Code:

`if (!(t=a[x]-a[--y]) || x-y==abs(t)) { ...`

a[] is array of 8x8 chess board, a[i] = j → Queen at (i,j)

a[x] is the newly placed Queen,

a[y] are previously placed Queens, y = 1 .. x-1

Since we placed 1 Queen per row, there is no need to check horizontal attacks.

We only need to test vertical attacks (1st test), and diagonal attacks (2nd test)

I would have return actual board (8-digit number), instead of steps required to solve it.

We could have returned same steps, but not really solved anything ...

http://users.rcn.com/liusomers/nqueen_demo/nqueens.html
(07-03-2022 06:31 PM)parisse Wrote: [ -> ]I think it's bad to increment a variable and simultaneously do an assignation, because it's confusing...

Agreed. I was just using that as a simple example to show the difference.

More realistic examples are commonly used expressions like

a[i++] vs

a[++i] which give different results.

In my younger days, I learned C after having learned BASIC, Pascal, COBOL, and Fortran. I was so impressed with C's terseness. The fact that

if ((a=b++)==c) was a legal statement was mind bending for me. Assign b to a, increment b, compare a and c and branch accordingly, all in one statement! Gotta love it. Granted, this

should not be done, but I thought it was so cool that it

could be done. I've hopefully matured since then. :-)

(07-03-2022 06:24 PM)Wes Loewer Wrote: [ -> ] (07-03-2022 02:18 PM)toml_12953 Wrote: [ -> ]Here's the entire C program:

Code:

main()

{

int x,y,r,s,t,n,a[9];

for(n=1000;n>0;--n){

r=8;

s=0;

x=0;

do{

a[++x]=r;

do{

++s;

y=x;

while(y>1)

if (!(t=a[x]-a[--y]) || x-y==abs(t)){

y=0;

while(!--a[x])

--x;

}

} while(y!=1);

} while(x!=r);

}

printf("%d",s);

}

What an interesting little program. I cannot begin to image what it is trying to calculate. Whatever it is doing, it repeats the exact same calculation 1000 times, and a[0] never gets initialized or used.

Do tell, what is this?

It's the nqueens problem from here:

Calculator Benchmark
(07-03-2022 03:42 AM)toml_12953 Wrote: [ -> ]Auto decrementing a variable appears to work in HPPL while incrementing doesn't.

Here's a snippet from a C program and an equivalent snippet in HPPL

Notice the assignment statement right in the IF statement.:

Code:

if (!(t=a[x]-a[--y]) || x-y==abs(t)){

y=0;

while(!--a[x])

--x;

}

Code:

IF (NOT(T:=A(X)-A(--Y)) OR X-Y==ABS(T)) THEN

Y:=0;

WHILE NOT --A(X) DO

--X;

END;

END;

Hello,

do yo program it from a PC with the Prime emulator, or directly on the Prime keyboard ?

(I have some difficulties to key in on the Prime directly, hesitating investing on a laptop PC. )

(07-04-2022 09:11 AM)OlidaBel Wrote: [ -> ] (07-03-2022 03:42 AM)toml_12953 Wrote: [ -> ]Auto decrementing a variable appears to work in HPPL while incrementing doesn't.

Here's a snippet from a C program and an equivalent snippet in HPPL

Notice the assignment statement right in the IF statement.:

Code:

if (!(t=a[x]-a[--y]) || x-y==abs(t)){

y=0;

while(!--a[x])

--x;

}

Code:

IF (NOT(T:=A(X)-A(--Y)) OR X-Y==ABS(T)) THEN

Y:=0;

WHILE NOT --A(X) DO

--X;

END;

END;

Hello,

do yo program it from a PC with the Prime emulator, or directly on the Prime keyboard ?

(I have some difficulties to key in on the Prime directly, hesitating investing on a laptop PC. )

I typed it in on my physical Prime G2

(07-03-2022 06:24 PM)Wes Loewer Wrote: [ -> ] (07-03-2022 02:18 PM)toml_12953 Wrote: [ -> ]Here's the entire C program:

Code:

main()

{

int x,y,r,s,t,n,a[9];

for(n=1000;n>0;--n){

r=8;

s=0;

x=0;

do{

a[++x]=r;

do{

++s;

y=x;

while(y>1)

if (!(t=a[x]-a[--y]) || x-y==abs(t)){

y=0;

while(!--a[x])

--x;

}

} while(y!=1);

} while(x!=r);

}

printf("%d",s);

}

What an interesting little program. I cannot begin to image what it is trying to calculate. Whatever it is doing, it repeats the exact same calculation 1000 times, and a[0] never gets initialized or used.

Do tell, what is this?

The reason it performs the same calculation 1000 times is because it was written for a fast PC where the time for a single run isn't measurable. If you do the calculation 1000 times, you can then normalize the result by dividing the runtime by 1000 to get the time it took to run it once. For very fast PCs you might have to increase the 1000 to 10000 or even 1000000 to get a meaningful time measurement.

Here's an ANSI/ISO BASIC (ParactBASIC compiler) program to perform the same function. See how I had to use a larger number to get the result?

Result:

876

Time: 0.00001229 seconds

Code:

`LET t0=time`

DIM a(9)

FOR n=100000 TO 1 STEP -1

LET r=8

LET s=0

LET x=0

DO

LET x=x+1

LET a(x)=r

DO

LET s=s+1

LET y=x

DO WHILE y>1

LET y=y-1

LET t=a(x)-a(y)

IF t=0 OR x-y=ABS(t) THEN

LET y=0

LET a(x)=a(x)-1

DO WHILE a(x)=0

LET x=x-1

LET a(x)=a(x)-1

LOOP

END IF

LOOP

LOOP WHILE y<>1

LOOP WHILE x<>r

NEXT n

PRINT s

LET t1=TIME-t0

PRINT USING "Time: %.######## seconds":t1/100000

END

(07-04-2022 09:41 AM)toml_12953 Wrote: [ -> ]The reason it performs the same calculation 1000 times is because it was written for a fast PC where the time for a single run isn't measurable.

Yes, once I understood that it was solving the nqueens problem, then the 1000 iterations made sense.

(07-03-2022 01:03 PM)Wes Loewer Wrote: [ -> ]⋮

For instance, in C and its descendants,

Now a and b are both 6. However,

In C, a is again 6 but b is 5 since a is not incremented until after the right side is evaluated. In CAS, a and b are both 6. So a++ in CAS is like ++a in C.

⋮

— some good and insightful comments (some of which got snipped out, & into “⋮”)… Reading this thread made me think of posing a little C++ challenge. If one were to add a single character to the first line of the C++ code below, one would enter the land of

undefined behaviour for versions of C++ before C++17:

Code:

`int a = 0,b = a;`

a=5;

b=++a;

a=5;

b=a++;

Years ago, I fixed some bugs of this sort in the Prime source code (likely back when it was the 39gII code base; if not then, just a bit later).

(07-08-2022 03:15 AM)jte Wrote: [ -> ]If one were to add a single character to the first line of the C++ code below, one would enter the land of undefined behaviour for versions of C++ before C++17:

Since it's only one character, I'm guessing it has something to do with making b a reference to a

I could see this potentially causing a problem with

This could be interpreted as either

1) evaluate a (5)

2) assign that value to a (since b refers to a) (a=5)

3) increment a, making a (and b) 6

or interpreted as

1) evaluate a (5)

2) increment a (a is now 6)

3) assigned the value in step 1 to a, so a is back to 5 again.

Am I on the right track?

(07-08-2022 05:00 AM)Wes Loewer Wrote: [ -> ]⋮

This could be interpreted as either

1) evaluate a (5)

2) assign that value to a (since b refers to a) (a=5)

3) increment a, making a (and b) 6

or interpreted as

1) evaluate a (5)

2) increment a (a is now 6)

3) assigned the value in step 1 to a, so a is back to 5 again.

Am I on the right track?

A+
In theory, some of the numbered steps could be broken down into smaller pieces when machine code is being generated (e.g., if an integer was larger than the architecture’s register size [such as 32-bit ints on a 16-bit CPU or 64-bit “long long” integers on a 32-bit CPU]); these smaller steps could be interleaved by the compiler (maybe assign half of an integer, do an increment on a lower half, do a carry into the upper half, assign the other half of an integer).

(Or… if we reach even further into theoretical possibilities: perhaps the machine code for a routine has all machine registers fully employed and the compiler doesn’t want to use a register simply to hold a “1” and knows that two registers always differ by 1 [and the architecture doesn’t have an increment instruction the compiler likes… how far can we reach?

], it could use those two registers to effect a ++ with something like “+=5” and a “-=4”… and then slap the assignment given in the source code right in the middle of that.)

This topic always reminds me of a disagreement I had, as an undergraduate, with another undergraduate (around 30 years ago, now!), over the validity of xor-swapping with chained xor-assignment (“a ^= b ^= a ^= b”) in C — my point being that the lack of

sequence points had such code also veering into

undefined behaviour. (Values are being used before they are known to have settled post-assignment.) Funnily enough, when I mentioned this to my daughter when we went running yesterday, I noted that ”the other undergraduate” need only have waited 30 years for me to be more convinced of his argument, as C++17 introduces additional sequencing constraints involving assignment operators.