Author Topic: Refresh my memory please, dealing with multiple '='  (Read 4417 times)

0 Members and 1 Guest are viewing this topic.

Offline Cobalt

  • QB64 Developer
  • Forum Resident
  • Posts: 878
  • At 60 I become highly radioactive!
    • View Profile
Refresh my memory please, dealing with multiple '='
« on: December 05, 2021, 01:08:49 pm »
So why do multiple '=' on the same line act like a comparative instead of assignment?

Code: QB64: [Select]
  1. A% = 101
  2. B% = A% 'Assignment =
  3. C% = A% = 99 'comparative =:  C% = 0(false)
  4. D% = A% = B% 'comparative =: D% = -1(true)
  5.  

I can't seem to remember why this is. That only the first = is treated as an assignment and all others as comparatives.
Granted after becoming radioactive I only have a half-life!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Refresh my memory please, dealing with multiple '='
« Reply #1 on: December 05, 2021, 01:29:42 pm »
You can skip IF... THEN... which are slower than a compare and an assign combined.

I just did one with a equation for a square this very day (and last night):
Code: QB64: [Select]
  1. Const ss = 600
  2. Screen _NewImage(ss, ss, 32)
  3. Window (-2, -2)-(2, 2)
  4. ' lets see if a, b = 1 and d = 0 this should be simple diamond
  5.  
  6. For y = -2 To 2 Step .001
  7.     For x = -2 To 2 Step .001
  8.         test = Abs(x) + Abs(y) - 1
  9.         PSet (x, y), _RGB32(255 * -1 * (Abs(test) < .003)) ' ideally this should be (Abs(test) = 0)
  10.     Next
  11.  

Allot of IF... THEN... are used for making an assignments of values to variables, using an compare evaluation can make the assignment without the slower and extra  IF... THEN which really won't effect flow of execution (branching) as an IF THEN would.

Offline George McGinn

  • Global Moderator
  • Forum Regular
  • Posts: 210
    • View Profile
    • Resume
Re: Refresh my memory please, dealing with multiple '='
« Reply #2 on: December 05, 2021, 06:39:13 pm »
What you are doing is really a logic test.

For example, using an IF statement, if I do:
Code: [Select]
IF (K=69)*(R>1)THEN {Do Something ...} 
What I am saying is K=69 returns a 0 or -1,  AND R>1 returns a 0 or -1. The * does not mean multiply, it acts as the logical AND. The division / is the logical OR.

You still need to do an IF statement if you want to perform something if the condition is TRUE or FALSE (See code below):

Code: QB64: [Select]
  1. K = 68
  2. R = 0
  3. IF (K = 69) * (R > 1) THEN PRINT "Both are TRUE" ELSE PRINT "Both are NOT TRUE"
  4.  
  5. K = 69
  6. R = 2
  7. IF (K = 69) * (R > 1) THEN PRINT "Both are TRUE" ELSE PRINT "Both are NOT TRUE"
  8.  
  9. K = 69
  10. R = 1
  11. IF (K = 69) / (R > 1) THEN PRINT "One is TRUE" ELSE PRINT "Neither are NOT TRUE"

The result of the first IF statement returns a 0 for BOTH conditions, where the second IF returns a -1 for BOTH, and the third IF returns a 0 and -1 respectively.

This was used in old BASIC code (can still be done today) when doing graphics, to test if a cursor was at the left, right, top or bottom of the screen, or to test if you pressed a specific key on the keyboard while at a specific location. Or used to detect collisions in games by comparing two location values.
____________________________________________________________________
George McGinn
Theoretical/Applied Computer Scientist
Member: IEEE, IEEE Computer Society
Technical Council on Software Engineering
IEEE Standards Association
American Association for the Advancement of Science (AAAS)

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Refresh my memory please, dealing with multiple '='
« Reply #3 on: December 05, 2021, 10:14:29 pm »
What you are doing is really a logic test.

For example, using an IF statement, if I do:
Code: [Select]
IF (K=69)*(R>1)THEN {Do Something ...} 
What I am saying is K=69 returns a 0 or -1,  AND R>1 returns a 0 or -1. The * does not mean multiply, it acts as the logical AND. The division / is the logical OR.

You still need to do an IF statement if you want to perform something if the condition is TRUE or FALSE (See code below):

Code: QB64: [Select]
  1. K = 68
  2. R = 0
  3. IF (K = 69) * (R > 1) THEN PRINT "Both are TRUE" ELSE PRINT "Both are NOT TRUE"
  4.  
  5. K = 69
  6. R = 2
  7. IF (K = 69) * (R > 1) THEN PRINT "Both are TRUE" ELSE PRINT "Both are NOT TRUE"
  8.  
  9. K = 69
  10. R = 1
  11. IF (K = 69) / (R > 1) THEN PRINT "One is TRUE" ELSE PRINT "Neither are NOT TRUE"

The result of the first IF statement returns a 0 for BOTH conditions, where the second IF returns a -1 for BOTH, and the third IF returns a 0 and -1 respectively.

This was used in old BASIC code (can still be done today) when doing graphics, to test if a cursor was at the left, right, top or bottom of the screen, or to test if you pressed a specific key on the keyboard while at a specific location. Or used to detect collisions in games by comparing two location values.


Why isn't this line throwing a Div by 0 Error?
Code: QB64: [Select]
  1. IF (K = 69) / (R > 1) THEN PRINT "One is TRUE" ELSE PRINT "Neither are NOT TRUE"
  2.  

It will if you use "\" instead of "/".

Offline George McGinn

  • Global Moderator
  • Forum Regular
  • Posts: 210
    • View Profile
    • Resume
Re: Refresh my memory please, dealing with multiple '='
« Reply #4 on: December 05, 2021, 10:36:08 pm »
The reason is that it isn't doing a division. It is doing the logical OR. The compiler knows (must know as this is an original feature of BASIC and I think you can do this in C) that K=69 is a logic check, not an assignment due to it being enclosed in parenthesis.

Why isn't this line throwing a Div by 0 Error?
Code: QB64: [Select]
  1. IF (K = 69) / (R > 1) THEN PRINT "One is TRUE" ELSE PRINT "Neither are NOT TRUE"
  2.  

It will if you use "\" instead of "/".
____________________________________________________________________
George McGinn
Theoretical/Applied Computer Scientist
Member: IEEE, IEEE Computer Society
Technical Council on Software Engineering
IEEE Standards Association
American Association for the Advancement of Science (AAAS)

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Refresh my memory please, dealing with multiple '='
« Reply #5 on: December 05, 2021, 10:51:57 pm »
Code: QB64: [Select]
  1. K = 69
  2. R = 1
  3. Print (K = 69)
  4. Print (R > 1)
  5. Print (K = 69) / (R > 1); "WTH???" 'Output>>>   -INF     D   is weird!!!
  6. If (K = 69) / (R > 1) Then Print "One is TRUE" Else Print "Neither are NOT TRUE"
  7.  
  8. 'Compare to this
  9. Print "Comparing:"
  10. K = 69
  11. R = 1
  12. Print (K = 69)
  13. Print (R > 1)
  14. Print (K = 69) \ (R > 1)  ' as expected comment out to try next line
  15. If (K = 69) \ (R > 1) Then Print "One is TRUE" Else Print "Neither are NOT TRUE"  ' Div by zero as expected!
  16.  
  17.  
  18.  

It's not printing "One is true" because one is true but because this "-INF     D " <> 0.
« Last Edit: December 05, 2021, 11:00:05 pm by bplus »

Offline George McGinn

  • Global Moderator
  • Forum Regular
  • Posts: 210
    • View Profile
    • Resume
Re: Refresh my memory please, dealing with multiple '='
« Reply #6 on: December 06, 2021, 01:48:28 am »
Let me see if I can explain this.

The \ operator returns the integer quotient, which drops the remainder. When divide by Zero, it returns infinity (PositiveInfinity (INF) or NegativeInfinity (_INF)), or NaN or -NaN (not a number) if expression2 is also zero. (I think that's right - I lost a lot of my math during the past 45 years!)

the / operator (which is used in most all division), returns the full quotient, which retains the remainder in the fractional portion as a decimal. When divide by Zero, it produces a Divide By Zero Exception.

They are both division, but perform two entirely different functions. And you can't mix operands either.

This explains the -NaN or the -INF you are getting. I have no idea where the "D" in your example is coming from.

However, for testing TRUE or FALSE, a -NaN or -INF is correctly interpreted as TRUE. It may not be a number or be infinite, but a condition is considered TRUE only of the result is negative.
Code: QB64: [Select]
  1. K = 69
  2. R = 1
  3. PRINT (K = 69)
  4. PRINT (R > 1)
  5. x = ((K = 69) / (R > 1))
  6. IF x THEN PRINT "x is TRUE"

Above, x=-INF, but works when you do the IF x THEN ... It tests as TRUE

In the beginning of BASIC, logical or unary operations had to be done using the math operands. (Unlike C/C++, Python and other languages that have logical AND == and OR !  and NOT !=). The reason my example doesn't give a divide by zero error is because BASIC treats these as unary or binary logic functions, and not math constructs. This only applies to the regular / operand. I'm not sure about when the \ operand came into use, but in every program I have ever written, seen, etc. logical true/false tests was constructed like a formula. When you put () around the logical test, like R=68: PRINT (R=69), you get the result of the logical (IS 68=69) rather than R becoming 69 as in an assignment or LET statement.

Today, I can write the following and it works:
Code: QB64: [Select]
  1. v1 = 12: v2 = 3
  2. y = v1 AND v2

However, back in the 1960's through to the early 1980's, the only way in BASIC to write this was:
Code: QB64: [Select]
  1. v1 = 12
  2. v2 = 3
  3. y = v1 = v2

Both give you the same result = 0 or FALSE using the Truth Table.

So if I wanted to write a complex, logical algebraic truth test, I can use regular math operands, even today in QB64, and the interpreter back then (the compiler today) will see that not as a math formula, but a logic test. But you need to use the regular operands, not the \ operand, which works differently.

That is why when I do "IF (K=69) * (R>1)" what this does is ask: IS K=69 AND R>1. When I do "IF (K=69) / (R>1)" it asks: IS K=69 OR R>1.

Same with "IF (K=69) <> (R>1)" asks: is K=69 XOR R>1. See snippet:
Code: QB64: [Select]
  1. ' *** Same a P XOR Q in Truth Tables
  2. K = 689
  3. R = 1
  4. PRINT (K = 69)
  5. PRINT (R > 1)
  6. PRINT (K = 69) <> (R > 1) ' *** I get 0 because 689=69 (FALSE) IS NOT OR 1>1 (FALSE) (The entire logic test passes as FALSE)

So especially in older programs, you see code like this (From a TI/99 BASIC program):
Code: [Select]
310 IF S=0 THEN 280
320 IF K=81 THEN 520
330 IF (K=69)*(R>1)THEN 390
340 IF (K=a3)*(C>3)THEN 410
350 IF (K=68)*(C<31)THEN 430
360 IF (K=88)* (R<22)THEN 453

Lines 310 & 320 are checking for actual values, where 330-360 are doing AND logic tests. (This code snippet is from a TI/99 BASIC program: MICRO SKETCH - A simple graphics program that allows you to move a block around the screen to draw a picture. The E, D, S, and X keys allow moving up, right, left, and down respectively. The T key will allow you to toggle between a block and a blinking block which can be used as an eraser. You will be able to draw any shape you desire on the screen). This part of the code checks to see if you are within the physical dimensions of the screen, from what I can tell.


Code: QB64: [Select]
  1. K = 69
  2. R = 1
  3. Print (K = 69)
  4. Print (R > 1)
  5. Print (K = 69) / (R > 1); "WTH???" 'Output>>>   -INF     D   is weird!!!
  6. If (K = 69) / (R > 1) Then Print "One is TRUE" Else Print "Neither are NOT TRUE"
  7.  
  8. 'Compare to this
  9. Print "Comparing:"
  10. K = 69
  11. R = 1
  12. Print (K = 69)
  13. Print (R > 1)
  14. Print (K = 69) \ (R > 1)  ' as expected comment out to try next line
  15. If (K = 69) \ (R > 1) Then Print "One is TRUE" Else Print "Neither are NOT TRUE"  ' Div by zero as expected!
  16.  
  17.  
  18.  

It's not printing "One is true" because one is true but because this "-INF     D " <> 0.
____________________________________________________________________
George McGinn
Theoretical/Applied Computer Scientist
Member: IEEE, IEEE Computer Society
Technical Council on Software Engineering
IEEE Standards Association
American Association for the Advancement of Science (AAAS)

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Refresh my memory please, dealing with multiple '='
« Reply #7 on: December 06, 2021, 09:13:10 am »
-1/0 has a remainder?!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Refresh my memory please, dealing with multiple '='
« Reply #8 on: December 06, 2021, 09:46:36 am »
Here's how it breaks down:

QB45 tosses an error with division by zero, just like tosses overflow errors when values go out of bounds.

C does neither of those things.

When coding QB64, Galleon asked which behavior set folks liked better. 

The user base chose INFinity and to allow overflow, so as to not halt program execution or toss error messages.

Thus we have the behavior that exists today.



As for the equal thing, that's simply QB45 convention carried through for compatibility's sake.  First equal is assignment, rest are comparionson.   BASIC doesn't have two operators for = and ==, so the first usage is = and the rest are == as fat as the compiler is concerned.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Refresh my memory please, dealing with multiple '='
« Reply #9 on: December 06, 2021, 09:56:26 am »
' *** Same a P XOR Q in Truth Tables
K = 689
R = 1
PRINT (K = 69)
PRINT (R > 1)
PRINT (K = 69) <> (R > 1) ' *** I get 0 because 689=69 (FALSE) IS NOT OR 1>1 (FALSE) (The entire logic test passes as FALSE)


This has nothing to do with XOR Truth tables.  It's just simple comparisons.

K = 69 is the same as 689 = 69...   FALSE, So it's 0.
R > 1 is the same as 1 > 1...  FALSE, So it's 0.
(K = 69) <> (R > 1) ....   Becomes 0 <> 0...  FALSE, So it's 0.

No XORs, ORs, or ANDs involved. Just basic number comparisons at work.

It's honestly not that complicated.

Edit: To highlight the fallacy in the logic, try this.

PRINT (K = 69) = (R > 1)

If this fallows the XOR truth table, then the result should be 0 as a False XOR False is False.  All you're doing, in the end, is comparing if 0 = 0, or not, and that's TRUE so the answer is -1.
« Last Edit: December 06, 2021, 10:09:20 am by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Refresh my memory please, dealing with multiple '='
« Reply #10 on: December 06, 2021, 10:01:29 am »
I'm sorry but this is just plain ridiculous!
Code: QB64: [Select]
  1. K = 69
  2. R = 1
  3. Print (K = 68)
  4. Print (R > 1)
  5. Print (K = 68) / (R > 1); "WTH???" 'Output>>>   NAN     D   is weird!!!
  6. If (K = 68) / (R > 1) Then Print "One is TRUE" Else Print "Neither are NOT TRUE"
  7.  
  8.  
  9.  

No OR test here with division.
« Last Edit: December 06, 2021, 10:21:43 am by bplus »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Refresh my memory please, dealing with multiple '='
« Reply #11 on: December 06, 2021, 10:14:46 am »
You're seeing division by zero, which folks chose to make results be NaN (Not a Number), rather than "ERROR: DIVISION BY ZERO".

In QBASIC, False is 0, *anything else* is true.  Since NAN isn't 0, it's TRUE.

It's the results the user base chose somewhere around version 0.2 when asked what they preferred to happen: Toss Errors and stop program execution, or make the result NAN.

Folks chose the NAN behavior, so now that's what we have.

As odd as it is, it was intentionally made that way by the vote of the majority of the user base.  Just like REM is a command, but ’ is a just a remark... 

Try
:

IF X THEN REM

vs

IF X THEN '

See the difference in behavior?  Folks CHOOSE that on purpose!

https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Refresh my memory please, dealing with multiple '='
« Reply #12 on: December 06, 2021, 11:51:07 am »
I am not complaining of the vote to avoid the Div by 0 error, though I think I would have voted different, I am saying the division trick or tip won't work as an Alternate OR test as it may once have done in another BASIC PL.

Offline George McGinn

  • Global Moderator
  • Forum Regular
  • Posts: 210
    • View Profile
    • Resume
Re: Refresh my memory please, dealing with multiple '='
« Reply #13 on: December 06, 2021, 12:34:56 pm »
@SMcNeill - I have a couple of questions then, and it has to do the the \ division operator, which converts to an integer division.

Why does this return a Divide By Zero Exception, and not a NaN or -NaN like when using the / operator?

Shouldn't it be consistent?


You're seeing division by zero, which folks chose to make results be NaN (Not a Number), rather than "ERROR: DIVISION BY ZERO".

In QBASIC, False is 0, *anything else* is true.  Since NAN isn't 0, it's TRUE.

It's the results the user base chose somewhere around version 0.2 when asked what they preferred to happen: Toss Errors and stop program execution, or make the result NAN.

Folks chose the NAN behavior, so now that's what we have.

As odd as it is, it was intentionally made that way by the vote of the majority of the user base.  Just like REM is a command, but ’ is a just a remark... 

Try
:

IF X THEN REM

vs

IF X THEN '

See the difference in behavior?  Folks CHOOSE that on purpose!
____________________________________________________________________
George McGinn
Theoretical/Applied Computer Scientist
Member: IEEE, IEEE Computer Society
Technical Council on Software Engineering
IEEE Standards Association
American Association for the Advancement of Science (AAAS)

Offline George McGinn

  • Global Moderator
  • Forum Regular
  • Posts: 210
    • View Profile
    • Resume
Re: Refresh my memory please, dealing with multiple '='
« Reply #14 on: December 06, 2021, 12:58:51 pm »
I do agree with you, and even in QB64, I've seen vintage code give me unexpected results because using the math operands today, even in QB64, do not quite work the way they once did.

I strongly suggest, as I do in my own code, to convert any old styled logic tests to use: NOT, AND, OR, XOR, EQV and IMP in its place, as these work.

I have seen the old way of using the / operator for OR not work properly in all cases. When I replace it with OR, it then works.

We did go a little off the rails, but I am hoping that others who read these will learn what can happen with old code if you just import it into QB64. While in most cases it works, there are situations where it will not work as expected, and the programmer needs to adapt!     




I am not complaining of the vote to avoid the Div by 0 error, though I think I would have voted different, I am saying the division trick or tip won't work as an Alternate OR test as it may once have done in another BASIC PL.
____________________________________________________________________
George McGinn
Theoretical/Applied Computer Scientist
Member: IEEE, IEEE Computer Society
Technical Council on Software Engineering
IEEE Standards Association
American Association for the Advancement of Science (AAAS)