SRL Archive - Lape

Chained and operator doesn't work?


m34tcode

2014-03-17 22:40:36

Writing a method to check whether a TPoint is within a valid range: 0 <= X < 8 and 0 <= Y < 8, this is what I have:

function TPoint.ValidPoint : Boolean;
begin
WriteLn(Self.x >= 0);
Result := Self.X >= 0 and Self.Y >= 0
and Self.X < 8
and Self.Y < 8;
end;

begin
WriteLn(Point(-1,0).ValidPoint);
end;

This returns False then True, although it should be False False.

If I change it to this it works

function TPoint.ValidPoint : Boolean;
begin
WriteLn(Self.x >= 0);
Result := not(Self.X >= 0 or Self.Y >= 0
or Self.X < 8
or Self.Y < 8);
end;

begin
WriteLn(Point(-1,0).ValidPoint);
end;

Edit: Further testing and if this function is tested on a point (-1,0) it returns the correct result, but anything else fails?

Turpinator

2014-03-18 01:16:22

function TPoint.ValidPoint : Boolean;
begin
WriteLn(Self.x >= 0);
Result := (Self.X >= 0) and (Self.Y >= 0)
and (Self.X < 8) and (Self.Y < 8);
end;

begin
WriteLn(Point(-1,0).ValidPoint);
end;
parentheses.

Or… with inRange()
function TPoint.ValidPoint : Boolean;
begin
WriteLn(self.x >= 0);
Result := inRange(self.X, 0, 7) and inRange(self.Y, 0, 7);
end;

begin
WriteLn(Point(-1,0).ValidPoint);
end;
When inRange is essentially result := (value >= min) and (value <= max);

slacky

2014-03-18 01:53:51

No parentheses in your if-statement results in a single bitwise operation. To get it correct you need to separate each comparison statement. So everything before 'or'/'and ' should be placed in each there parentheses to evaluate each case individually. If you call a function which evaluates some case, that will be the same as using parentheses (EG: using InRange).

So:
> R := (X >= 0) and (Y >= 0) and (X < W) and (Y < H);
Or:
> R := InRange(X, 0, W-1) and InRange(Y, 0, H-1);

Brandon

2014-03-18 09:33:53

From: slacky
No parentheses in your if-statement results in a single bitwise operation.



What are you talking about :S What do you mean "single bitwise operation" is being performed? These are logical operations being done.


Consider:


bool valid()
{
return this->X >= 0 && this->Y >= 0 && this->X < 8 && this->Y < 8;
}

bool bitwise()
{
return this->X >= 0 & this->Y >= 0 & this->X < 8 & this->Y < 8;
}


Or


boolean valid()
{
return this.X >= 0 && this.Y >= 0 && this.X < 8 && this.Y < 8;
}

boolean bitwise()
{
return this.X >= 0 & this.Y >= 0 & this.X < 8 & this.Y < 8;
}


Or


Function TPoint.ValidPoint : Boolean;
Begin
Result := Self.X >= 0 and Self.Y >= 0
and Self.X < 8
and Self.Y < 8;
End;


Function TPoint.Bitwise : Boolean;
Begin
Result := Integer(Self.X >= 0) and Integer(Self.Y >= 0)
and Integer(Self.X < 8)
and Integer(Self.Y < 8);
End;

Or:


format PE console
entry main

include 'Code/FASM/include/macro/import32.inc'

section '.idata' import data readable
library msvcrt,'msvcrt.dll'
import msvcrt, printf, 'printf',\
exit,'exit', getchar, 'getchar', scanf, 'scanf'


section '.data' data readable writeable
True db "true", 0
False db "false", 0
Response db 13, 10, "The point is valid: %s", 13, 10, 0
Value db 13, 10, "Value: %d", 13, 10, 0

struc Point X, Y
{
.X dd X
.Y dd Y
}

P Point -0x0, 0x08

section '.code' code readable executable
main:
push ebp
mov ebp,esp

;push dword -0x01 ;Point.X
;push dword 0x00 ;Point.Y
push dword [P.X]
push dword [P.Y]
call Point_Valid
add esp, 0x08

cmp eax, 0x01
jge .true
jmp .false

.true:
push True
jmp .end
.false:
push False
.end:

push Response
call [printf]
add esp, 0x08

mov esp, ebp
pop ebx

call [getchar]

mov eax, 0x00
ret

Point_Valid:
push ebp
mov ebp, esp

mov edx, 0x0
mov eax, [ebp + 0x0C] ;Point.X
call Greater_Than_Equal ;Is Point.X >= 0?
mov edi, eax

mov eax, [ebp + 0x08] ;Point.Y
call Greater_Than_Equal ;Is Point.Y >= 0?
and edi, eax

mov edx, 0x08
mov eax, [ebp + 0x0C] ;Point.X
call Less_Than ;Is Point.X < 8?
and edi, eax

mov eax, [ebp + 0x08] ;Point.Y
call Less_Than ;Is Point.Y < 8?
and edi, eax

mov edx, eax

mov esp, ebp
pop ebp
ret

Greater_Than_Equal:
cmp eax, edx

jge .true
jmp .false
.true:
mov eax, 0x01
jmp .end
.false:
mov eax, 0x00
.end:
ret

Less_Than:
cmp eax, edx
jl .true
jmp .false
.true:
mov eax, 0x1
jmp .end
.false:
mov eax, 0x00
.end:
ret


So what is wrong with it? No parenthesis in any of them.. But, only one of the examples above prints the wrong values.. And that example is: TPoint.ValidPoint


Thus something is wrong with Simba.. Short-Circuit Boolean evaluation here applies.. Hand wrote that assembly (a bit rusty) and it does the same job Simba should be doing.. It doesn't take into account short-circuit boolean evaluation though.

The only time Simba should fail is if one of the and statements BEFORE the last instruction (before the last and statement) becomes false with {B+} as the pre-processor instruction, then short-circuit boolean evaluation is valid.


Simba/Lape should have similar instructions to what C, C++ and Java is doing.. but it doesn't.. Something is wrong then. OP's first block of code is perfectly valid even in languages that take short-circuit boolean evaluation into account and should not require any parenthesis at all.

Kevin

2014-03-18 10:26:57

o.O

Nothing is wrong with Simba. The logic is working correctly in every case I've seen. I agree with Slacky, although will try to explain with more detail.

Without parenthesis, there is nothing to specify the order of operations, as 'and' and comparators (ie: '>=') have equivalent order times. Therefore your logic says:
result1:= Self.X >= 0;//False
result2:= result1 and Self.Y;//FALSE - 0 && 0
result3:= result2 >= 0;//TRUE 0 >= 0
result4:= result3 and Self.X;//True. I think? 1 and -1. bitwise true at least.
result5:= result4 < 8;//True for sure. 1 < 8
result6:= result5 and Self.Y;//False. 1 and 0
result7:= result6 < 8;//True. 0 < 8

Brandon

2014-03-18 11:30:24

From: Kevin
o.O Nothing is wrong with Simba. The logic is working correctly in every case I've seen. I agree with Slacky.




In Simba:


var
I: Integer;
begin
I := true;
end.

Gives the error:

Exception in Script: Can't assign "False..True(4294967295)" to "Int32" at line 4, column 5


and rightfully so because booleans are strongly typed.


According to your logic and Slacky's:


var
Result1, Result2: Boolean;
X, Y: Integer;
begin
X := -1;
Y := 0;

Result1 := X >= 0;
Result2 := Result1 and Y;
end;

The above is fine.. And in fact, it does compile now.. However, there is one massive problem.

The implicit conversion of Result1 to a LongInt in order to "bit-wise and" it with Y.

This is wrong because as shown before, booleans are strongly typed and cannot be converted to an integer without an explicit cast.

Thus the "and" operator MUST/SHOULD do logical-and and not a bit-wise and..


In fact, it is disallowed by FPC and GPC: http://ideone.com/i4lRMP

Notice the compilation error at line 10 and below?

As for Simba: http://en.wikipedia.org/wiki/Comparison_of_Pascal_and_C#Implementation_issues

It says under Implementation Issues that "Pascal doesn't allow the mixing of arithmetic and Boolean variables, and things like this are caught at the semantic level, when it comes time to generate code for them, rather than at the syntax level."

Referring to: x + (y AND NOT z) DIV 3


So not only should Lape be doing Logical-And, it also doesn't have its semantics right when it comes to boolean evaluation..

You can try the above in FPC or GPC and see it won't get as far as compiling.. So again, Simba/Lape has yet another issue with semantics..


As pointed out in my previous example:


Function TPoint.ValidPoint : Boolean;
Begin
Result := Self.X >= 0 and Self.Y >= 0 //No explicit casts.. Should be doing Logical-And or Compile-Time-Error
and Self.X < 8
and Self.Y < 8;
End;


Function TPoint.Bitwise : Boolean;
Begin
Result := Integer(Self.X >= 0) and Integer(Self.Y >= 0) //Explicit casts.. Does Bitwise-And.
and Integer(Self.X < 8)
and Integer(Self.Y < 8);
End;

Kevin

2014-03-18 11:54:57

From: Brandon
…


I do see your point now and how it should react, having noted the dis-allowance of automatic boolean casting and FPC guidelines. With that noted… It is possible that LAPE is instead treating all "bool and int" scenarios as automatically false as opposed to a compile-time error. It would still allow for the final result I mention before to be true, and it could be determined quickly from a single command.

Writeln(1 and true);//If True, then an invalid bit-wise comparison is occurring.  If False, then the runtime invalidation should be a compile time error.

I'd run it myself to determine which is at fault, however I do not have access to Simba atm… I can check in a few hours.

slacky

2014-03-18 11:56:10

From: Brandon
What are you talking about :S What do you mean "single bitwise operation" is being performed? These are logical operations being done.

Simba/Lape should have similar instructions to what C, C++ and Java is doing.. but it doesn't.. Something is wrong then. OP's first block of code is perfectly valid even in languages that take short-circuit boolean evaluation into account and should not require any parenthesis at all.

Aha.

I peaked at this piece some time ago, and it lead me to believe that "such statements" was bitwise:
http://en.wikipedia.org/wiki/Comparison_of_Pascal_and_C#Bitwise_operations
^ I most likely peaked to fast then.

I have not really used, and read to much about bitwise operations in Pascal (or in general), but I believed that statement like
R := X >= 0 and Y >= 0 and X < 8 and Y < 8;
Was evaluated the same way as the Python piece (using the bitwise and-operator):
R = X >= 0 & Y >= 0 & X < 8 & Y < 8;

Where both will result in False (IE with X=4, and Y=4).


Edit:
> Brandon, thank you for your further elaboration, it seems to have cleared up some stuff :)

Brandon

2014-03-18 12:45:12

From: slacky
Aha.

I peaked at this piece some time ago, and it lead me to believe that "such statements" was bitwise:
http://en.wikipedia.org/wiki/Comparison_of_Pascal_and_C#Bitwise_operations
^ I most likely peaked to fast then.

I have not really used, and read to much about bitwise operations in Pascal (or in general), but I believed that statement like
R := X >= 0 and Y >= 0 and X < 8 and Y < 8;
Was evaluated the same way as the Python piece (using the bitwise and-operator):
R = X >= 0 & Y >= 0 & X < 8 & Y < 8;

Where both will result in False (IE with X=4, and Y=4).


Edit:
> Brandon, thank you for your further elaboration, it seems to have cleared up some stuff :)



The thing is that Python has two different operators for this.

http://ideone.com/WcKSq8


X = 0
Y = 0

Result1 = X >= 0 and Y >= 0 and X < 8 and Y < 8;

Result2 = X >= 0 & Y >= 0 & X < 8 & Y < 8;


str1 = "{}{}".format("One: ", Result1)
str2 = "{}{}".format("Two: ", Result2)

print (str1) #True Logical
print (str2) #False Bitwise (like you said)

But Simba has one? I think that's where the problem lies; other than the comparison not being allowed in FPC.