Hi all. I have a graphic program on a 320x240 x=320.,y=240 display.
I use word values for the x,y position of a space---chr 32.
I use a xdirection and ydirection to move the space. These are word values.
I add the xdirection to xposition and ydirection to yposition to move the space.
if xdirection=4 then it moves 4 pixels right. if xdirection is 65535-4 then it moves -4 pixels left.
You can't define a variable as a minus number in gcb so I'm using the over flow feature.
My question is how to make positive numbers negative number and negative nubers positive without if then.
Where 1234 are plus and 65534,65533,65532,65531 are -1,-2,-3,-4
0 and 65535 seem the same?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
ifxdirection<255then; xdirection is plus valuexdirection=65535-xdirection; make it minus valueelse; xdirection is minus valuexdirection=65535+xdirection; make xdirection plus valueendif
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Negative numbers in Binary are represented by 2's complement notation with the Most significant bit (that is bit 15 in a 16 bit Variable) being the sign bit. However the interpretation of the sign is dependent on the variable type and that is where GCBASIC is a little confusing, as are all languages.
In GCBASIC:
Integer is a 16 bit signed variable with a range of -32768 and 32767
Word is an unsigned 16 bit integer with a range of 0 and 65535
So you should be using Integer not Word if you need 16 bit signed values.
Cheers
Chris
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thanks for replying.
The screen is 320 by 240, I used word values for x,y position and word values for x and y direction.
To change x or y direction from + to - ,or - to + , I just say ball_xdirection=65535-ball_xdirection.
I then say ball_x=ball_x+ball_xdirection.
No if then testing.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Sorry but I thought you were asking a question not making a statement.
If you are happy using an unsigned integer (word) to represent negative values I will leave that to your better judgment.
If you would prefer to do it in a way that others can understand then use signed Integer variables instead of unsigned Word Variables.
For the sake of others reading this thread the correct way to form a 2’s complement (i.e. negate a number in binary) is:
ball_xdirection = 1 + NOT ball_xdirection
This works because a 2's complement number is the Complement of the Number Plus One and the above will work regardless of the variables Bit length so is valid for byte, integer and long variables types.
Cheers
Chris
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I'm confused. I thought not was for a bit like port a=!port a. I didn't realise it worked for byte.
but then and or do. Silly me.
"integer is a 16 bit signed variable with a range of -32768 and 32767" I don't understand that.
I though integer was 0-255.
negative numbers are covered where in help?
so dim ball_xdirection as what? it has be word for 16 bit?
how would I define ball_xdirection=-4? would that be 32765 ?
and would 4 be 32770?
I changed ball_xdirection=65535-ball_xdirection to
ball_xdirection=1+not ball_xdirection
and it runs the same!
so I am using a sign word variable?
which method would be fastest and less code memory?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
You raise a valid point and one that many computer users forget to explain so I think we need to look at a few basics - pun intended - as you are not alone in your confusion over variables and types. I will break it down into small chunks to try and simplify it for everyone.
It will, however, be a long post though so give me a few minutes / hours to get my thoughts down in text and post it here.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I changed a few start values for ball and bats and found the xdirection dropping to 0.
so changed instances of ball_xdirection=1+not ball_xdirection back to 65535-ball_xdirection and it works.
I have a game in the demos,tron,where I use 255 for-1 and Evan thought it was cool. Not I'm doing it wrong.
Negative numbers needs explaining in help and the bit about U L H is confusing. The help could be improved.
random numbers between a range say 1 to 4 could be explained
random/85+1 ?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I'm sort of pleased I worked out 65535-word changes it to a minus number and visa versa if it was negative when added to another word variable.
I couldn't find anything in help to help.
I think it works for byte vars. ie 255-bytevar changes it's sign when added to another bytevar.
"it should drop to Zero that is part of the definition of an integer."
it's supposed to make 4=-4..not reduce it to 0. each time the ball hit a certain condition the xdirection dropped by 1 using 1+not wordvar.
If I'm to make my code more easy for other users to understand then I'm told to use the method suggested as if it was common knowledge. Well it's a shame that "the normal way to use negative numbers that others can understand" isn't mentioned.
So other users won't understand 65535-word changes it's sign?
While on the subject of gcb users knowledge, is goto allowed anymore?
In this program
set up glcd and dim, init vars
start:
do
program
if condition goto start ie goal scored or player 1 or 2 won
loop
I don't want to use goto because it's supposed to be not used but seems a simple way.
I hope my comments don't upset anyone like why doesn't stan get another simpler hobby :)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
It's not I'm jumping out of a sub and is there a stack of retun addreesses that will overflow.
Structure????
Respect but the program is in line ie no subs. I use multiple if thens instead of logical operator and. It's all about speed so make my code fast as possible eg if the ball is going left then check right bat back and left bat front AND left border and scored goal. Same for ball going right.
Checking top and bottom border is separate and did check left and right border before.
If you're doing games,they must run fast!
If I made the main do loop a sub could I exit it so it went to next command after calling it eg
sub game
other stuff
sub game
do
program
condition=end sub
loop
end sub
?
one goto start would be easiest because when a goal is scored the program reinitialises vars except scores, clears and re- draws screen ie starts again...the initial ball x,y direction being random.
If you can advise me to how to make my code structured without extra code and run at same speed then my ears are on.
I have written programs that sub common code and the main program looks shorter but to see what's happening you have to scroll to the sub to see what's happening.
Structured code seems inefficient...and not easier to read imho :)
Code so far for those interested. I'm open to comments.
#chipmega328p,16
#include<glcd.h>
#optionexplicit;--------------
#defineGLCD_TYPEGLCD_TYPE_ILI9341
#defineGLCD_DCportb.0; DIGITAL_8 ' Data command line
#defineGLCD_CSportb.2; DIGITAL_10 ' Chip select line
#defineGLCD_RESETportb.1; DIGITAL_9 ' Reset line
#defineGLCD_DIportb.4; DIGITAL_12 ' Data in | MISO - Not used therefore not really required
#defineGLCD_DOportb.3; DIGITAL_11 ' Data out | MOSI
#defineGLCD_SCKportb.5; DIGITAL_13 ' Clock Line
#defineILI9341_HardwareSPI' remove/comment out if you want to use software SPI.
#defineGLCD_EXTENDEDFONTSET1;-----------------------------;now rename colours to make it faster to type colours
#definebkILI9341_BLACK
#definereILI9341_RED
#definegrILI9341_GREEN
#defineblILI9341_BLUE
#definewhILI9341_WHITE
#definepuILI9341_PURPLE
#defineyeILI9341_YELLOW
#definecyILI9341_CYAN
#definedgILI9341_D_GRAY
#definelgILI9341_L_GRAY
#definesiILI9341_SILVER
#definemaILI9341_MAROON
#defineolILI9341_OLIVE
#defineliILI9341_LIME
#defineaqILI9341_AQUA
#defineteILI9341_TEAL
#definenaILI9341_NAVY
#definefuILI9341_FUCHSIA;;GLCDBackground = whGLCDRotate(landscape)GLCDCLSwhdimleftgoals,rightgoalsasbytedimball_x,ball_y,last_ball_x,last_ball_yasWorddimball_width,ball_heightasBytedimball_xdirection,ball_ydirectionasworddimleftbat_y,rightbat_y,leftbat_x,rightbat_xasWorddimleftbat_height,rightbat_heightasBytedimleftgoal_ytop,leftgoal_ybottom,rightgoal_ytop,rightgoal_ybottomasWorddimtop_edge,left_edgeasbyte; they are zerodimbottom_edge,right_edgeasWord;screen resolutiondimtmpasbytedimcountasword'dim leftpot,rightpot as Byte'leftgoals=0:rightgoals=0start:
leftbat_x=64:rightbat_x=256leftbat_y=100:rightbat_y=100top_edge=0:left_edge=0:right_edge=319:bottom_edge=239'bat_height=24;init ball --------ball_x=160 :ball_y=112;mid screenlast_ball_x=ball_x:last_ball_y=ball_y;ball direction at Startup--------------;x direction ---------------------tmp=Randomiftmp.1=0then;is random odd or even numberball_xdirection=8elseball_xdirection=65535-8endif;y direction -----------------------tmp=Randomiftmp.0=0then;is random odd or even numberball_ydirection=4elseball_ydirection=65535-4endif;draw border -----------------------filledbox8,9,311,231,bk;draw left goal --------------------FilledBox0,80,8,160,bk;draw right goal ---------------------FilledBox311,80,319,160,bkGLCDDrawString(0,0,"TOP___TOP",bl)do;main program;draw batsGLCDBackground=whforcount=leftbat_ytoleftbat_y+24step8;draw 4 spacesGLCDDrawChar(leftbat_x,count,32)nextcountforcount=rightbat_ytorightbat_y+24step8;draw 4 spacesGLCDDrawChar(rightbat_x,count,32)nextcountifball_xdirection<32767then;--going right;check ball hit right wall-----ifball_x+ball_xdirection>=306thenifball_y>=80thenifball_y<=152thenleftgoals++;----------------------Goto start ????????endifendifball_xdirection=65535-ball_xdirection;--go leftendif;;check if ball hit left bat back------ifball_x+7<leftbat_xthenifball_x+ball_xdirection+8>=leftbat_xthenifball_y+7+ball_ydirection>=leftbat_ythenifball_y+ball_ydirection<=leftbat_y+31thenball_xdirection=65535-ball_xdirection;--go leftendifendifendifendif;;check if ball hit right bat front------ifball_x+8<rightbat_xthenifball_x+ball_xdirection+8>=rightbat_xthenifball_y+7+ball_ydirection>=rightbat_ythenifball_y+ball_ydirection<=rightbat_y+31thenball_xdirection=65535-ball_xdirection;--go leftifball_ydirection>=0thenball_ydirection=random/63elseball_ydirection=65535-random/63endifendifendifendifendif;else;ball going left;;check ball hit left wall------ifball_x+ball_xdirection<=8thenifball_y>=80thenifball_y<=152thenrightgoals++'-------------------GOTO start ??????endifendifball_xdirection=65535-ball_xdirection;--go rightendif;;check if ball hit right bat back------ifball_x>rightbat_x+8thenifball_x+ball_xdirection<=rightbat_x+8thenifball_y+7+ball_ydirection>=rightbat_ythenifball_y+ball_ydirection<=rightbat_y+31thenball_xdirection=65535-ball_xdirection;--go rightendifendifendifendif;;check if ball hit left bat front------ifball_x>leftbat_x+8thenifball_x+ball_xdirection<=leftbat_x+8thenifball_y+7+ball_ydirection>=leftbat_ythenifball_y+ball_ydirection<=leftbat_y+31thenball_xdirection=65535-ball_xdirection;--go rightifball_ydirection>=0thenball_ydirection=random/63elseball_ydirection=65535-random/63endifendifendifendifendifendif;-------------;check if ball hit top or bottom border ----------------------ifball_ydirection<32767thenifball_y+ball_ydirection>=224then;--going downball_ydirection=65535-ball_ydirection;--go upendifelseifball_y+ball_ydirection<=8thenball_ydirection=65535-ball_ydirection;--go downendif;;move ball x ------------------------------ball_x=ball_x+ball_xdirection;move ball y --------------------------------ball_y=ball_y+ball_ydirection;eraseball ---------------------------------GLCDBackground=bkGLCDDrawChar(last_ball_x,last_ball_y,32);plotball ---------------------------------------GLCDBackground=whGLCDDrawChar(ball_x,ball_y,32);update last ball x,y -------------------last_ball_x=ball_x:last_ball_y=ball_y;wait 100 msloop'
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
If I've dimmed a var then It's value is 0..yes?
so I don't need to define those vars as 0 if they should start at 0?
eg dim var as byte
var=0 ;---not needed?
saves code
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
help says undefined var is zero.
I play safe and give values but if I can save code then I do.
update help again. Can I use a text editor to change help files and submit for whoever's approval? A few more examples maybe in a different stylee? eg this issue.
imho help needs updating. It's good but incomplete and examples seem complicated...cos they're pic. I'm not moaning, just positive thoughts....also as posted negative thoughts :)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
This is an attempt to clarify the different types and sizes of data variables used by GCBASIC and how they are interpreted or handled by GCBASIC Functions and to give a better Idea of which type to use when. Much of this holds true for any programming language so I will point out a few issues of Code Portability as I go.
Unfortunately it is not possible to do the topic justice without teaching a bit of Computer science theory at the same time but I will attempt to keep it light hearted and not too dry.
Why do we have so many different variable Sizes?
In computer science numbers are represented in Binary and have specific sizes set by the Memory or Register Size and the ALU (Arithmetic Logic Unit) of the device that is acting on the data.
Common sizes are Bit (1 Bit), Nibble (4 Bit), Byte (8 Bit), Word (16 Bit), Long (32 Bit) and Long Long (64 Bit).
GCBASIC has Bit, Byte, Word and Long Variable Types, all of which are described below, but it has no Long Long (64 Bit) type as yet.
Bit is used as a Flag or a Port Pin and has two states ON/OFF - TRUE/FALSE - HIGH/LOW - 1/0 - SET/RESET and many other complementary states Depending on how your application interprets and handles the data.
Byte is the most common variable size in 8 Bit devices and could represent a Number, an ASCII Character, a Port, two Nibbles (Think Hex or BCD), an Internal Register or any user defined collection of Bits such as Flags.
Word is normally used for its Numeric value. 16 Bits will allow it to store Numbers from Zero to 65535 which is large enough to store the product of any two 8 bit Bytes without overflowing. However, it is not confined to being used as a numeric value. It may be used in any manner that your application needs depending on how it interprets the 16 Bits of data. Examples may be a memory address or data pointer.
Note: the Word variable type in GCBASIC, or any other language, has nothing to do with the Word Size of the ALU (Arithmetic and Logic Unit). The Word size of a device (as opposed to the Word Type above) is a representation of the number of Bits that it can manipulate simultaneously in the ALU. The Word Size is generally 4 Bits in older Microprocessors (intel 4004) to 64 Bits in modern computer and 4G devices. The ALU size of the PIC and AVR Microcontrolers supported by GCBASIC are 8 Bits and so they are considered to have an 8 Bit Word.
Long is for situations where Values exceeding 65535 have to be handled and has a range of zero to 4.29 Billion. It is rarely used in 8 Bit devices but is invaluable on the rare occasions that it is needed. The Millis function uses the Long Data Type to handle long time periods
All of the above can be considered to be Integer Values of varying magnitude as they can hold non Fractional Positive Whole Numbers, but try not to confuse Integer Values with the Integer Variable Type, they are complementary but separate concepts as you will see below.
In the real world.............
An integer is a Mathematical Construct that represents a whole number (not a fractional number) that can be Positive, Negative, or Zero. Of itself the Integer is not a computer construct but is a root principal of Mathematics.
In real world applications we also need to be able represent Negative Numbers in our variables and that is where the GCBASIC Integer Variable Type enters the discussion. An Integer Variable is exactly the same as a Word Variable as they are both 16 bits and can store a positive whole number. The difference is not in the Physical storage but rather how the Compiler Interprets the bits that it contains.
The compiler will treat a Word Variable Type as a Variable that can store the values 0 < 65535 but it will see the Integer Variable Type as a Variable that can store values of -32768 < 0 <32767.
In Computer Science the GCBASIC Word Variable type would be called an Unsigned Integer and the otherwise identical Integer Data type would be a Signed Integer.
The modern way to refer to such types is:
Uint16_t for an Unsigned 16 bit Integer Value and Int16_t for a Signed 16 Bit Integer Value.
As you can see that eliminates the conflict between Word Size and the Size of a Word Variable as well as the Definition of an Integer Variable as opposed to a Word Variable both of which are 16 bit values.
One Size does not fit all
A lot of confusion comes from the Type definitions of the chosen language, in this case GCBASIC these are:
Byte(8Bit)Integer/Word(16Bit)Long(32Bit)
All 4 of the above are Integers in that they are representations of a non fractional number:
8Bits-0to25516Bits-0to6553532Bits-0to43294967295
But they can only represent positive numbers. In Mathematics we need an Integer that can be Positive, Negative, or Zero. Note that Zero is a Positive Whole Number.
To add to the confusion (and hindering code portability) different implementations of C and C++ as well as versions of BASIC, PASCAL, FORTRAN and FORTH all use different sizes of Integer as the default integer size.
They also differ in the declaration of signed vs unsigned Integers.
In order to avoid confusion modern languages now encourage the use of more specific types such as:
Int8_tInt16_tInt32_tInt64_t
And the Unsigned Equivalents
Uint8_tUint16_tUint32_tUint64_t
Such descriptive types help when porting and debugging code.
To correlate the GCBASIC variable Type when porting code between Arduino and GCBASIC here is a list of Equivalents that you may use:
As noted above, the mathematical definition of an integer also requires that it be able to represent a negative number but the computer has no such concept.
In mathematics, a negative number is a positive number prefixed by a ‘-’ (minus) symbol. So in order to distinguish a negative from a positive number in binary we use a sign Bit. If the Most significant bit is Set (1) the value is negative if it is Clear (zero) the number is positive.
But this simple solution would have repercussions:
The loss of a bit to represent the sign halves the magnitude of the variable.
It allows the possibility of a Negative Zero
Most ALU’s can only Add and Shift so they have no concept of negative.
There is, however, a simple trick in Binary mathematics called the Two's Complement that overcomes all but the magnitude issue as the Most Significant Bit is still a sign bit.
Two's Complement
To take the Two's Complement of a number it is inverted then incremented:
MyVar = NOT MyVar + 1
The increment has two effects, it avoids the possible creation of a negative zero as a value of 1000000 would be seen as -128 and it allows subtraction to be achieved through addition.
In the above if MyVar contained a value of 1 in an 8 Bit ALU that would be:
00000001
The NOT will make it
11111110
Note that the Most significant Bit is now 1 so the value is negative.
The increment will result in a value of:
11111111
So Minus one using an 8 Bit ALU in Two's Complement notation is 11111111
Let's test it by adding -1 to plus 3
11111111-100000011+3--------000000102
We have successfully subtracted 1 from 3 by adding Minus 1 to 3 and obtaining a result of 2.
And thanks to Computer science we can now answer Shakspear’s centuries old question: 2B OR NOT 2B = -1
Notice that whilst a Byte is normally used to represent 0 < 255 by making the MSB (Most Significant Bit) into a sign bit the maximum value is now 127. A signed 8 Bit integer can represent numbers in the range -128 < 0 < 127. That is still 256 values including Zero but they can now be Negative or Positive numbers.
The benefit of the two's complement method is that it works for any size of variable:
All of the above will result in a Negated version of the original contents.
But not all, in fact relatively few, functions of a Microcontroller require negative values so in situations where negative values are not required the loss of half of the magnitude of a Byte or Word can be significant. That is why it is necessary to be able to specify if a value is Signed or Unsigned, that is if the MSB is the sign bit or part of the value.
It is obviously important from the above that the Program or Functions need to know what sort of data to expect as a value of 0xFF could be considered to be both 255 and -1 depending on the interpretation of the variable. That is why it is important to have Signed and Unsigned Data Types so that the compiler can decide how to handle or interpret the contents. As we saw above in GCBASIC those types are referred to as Integer and Word respectively.
In conclusion ..............
The Negative Number is a Mathematical Construct that can be represented in Microcontrolers as a two’s complement number of arbitrary length. The Microcontroller itself has no concept of Negative numbers and the ALU is not able to perform a subtraction. It subtracts by adding the Two’s Compliment of the value it wants to subtract.
A Two's Complement number can be any bit size, in the case of GCBASIC there is only one Signed Variable Type Defined, that is the Integer Type which is used to hold an Int16_t value. That is a Signed 16 bit Integer with a value range of -32768 < 0 <32767.
There is nothing wrong with treating any variable Type as signed and as seen you can even take the two’s compliment of a Byte and add it to another Byte in order to subtract one byte value from another. But the Maths Functions of GCBASIC are intended to work with Signed 16 bit integers and will fail to compile if you try to use a signed 8 Bit or Signed 32 bit values.
I hope this helps clear things up and, if it is found to be useful, I will refine it further and try to answer any specific questions before placing it in the HELP Documentation.
Cheers
Chris
Last edit: Chris Roper 2019-10-23
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
There are stranger things happening in glcd include with different displys ie out of screen co-ordinates. varying efects depending on screen model and size. Decreasing x,y below zero has different effects. I have a few different glcds because gcb supported them and different results.
ssd1309 it wraps around the screen. ili series it takes a while to wrap around...if it does
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
remember, GLCD memory or x,y coordinates are handled by the LCD controller. Some controllers wrap the memory others do not. Hence, the difference. Programs may have to handle, or, you can use GLCDOverrunProtection.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Back to word math.
-2 -1 0 1 2
655534 65535 0 1 2
To change a variable sign +- it's 0-var not 65535-var which the compiler accepts and works.
Before 65535-1=-2 now 0-1=65535
and 0-65535=1...well it seems to work in the game. I should print vars on screen.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Chris-How to dim word or byte as signed please.or is that in help and I missed it?
var=0-var seems to invert it's sign but not printed out results yet.
I'll try changing every instance of var=0-var to var=1+not var and see.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Word type is an Unsigned (Uint16_t) but the Integer type is a Signed (Int16_t) so there no need to dim word as Signed just use Integer instead.
You can't Dim a Byte as Signed in GCBASIC the only signed Type that it recognised is the Integer Variable (Int16_t). But that does not prevent you form using a Byte as if it were signed.
Any variable is just a collection of Bits. The interpretation of the meaning of those bits is entirely up to you. It could be a Character, a Signed Number, and unsigned number etc. The Device you send it too will also trate it in the format it expects signed or unsigned regardless of how it is defined in GCBASIC.
var=0-var seems to invert it's sign but not printed out results yet.
That is because GCBASIC has to convert it to two's Complement in order to perform the subtraction. All you are achieving there is less efficient code.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
"var=0-var seems to invert it's sign but not printed out results yet.
"That is because GCBASIC has to convert it to two's Complement in order to perform the subtraction. All you are achieving there is less efficient code."!!!!!!!!!!!!
So the compiler converts 0-var to 1+ not var instead I write 1+not var and the compile accepts that and doesn't convert it?
So although the basic code is longer and using not should be slower in reality the compiler makes it more asm?
Well your way works and I can understand it but did use 0-random/63 as it;s a byte and it can be added to a word. How would you go about adding a minus 8bit random number to a word
As the the topic was about word math then you could have explained better adding a negative word to a word an explaining the overflow.
Again thank you for trying to explain things. It needs explaining in variables help or people like me try to figure it out ourselves...and don't get it right.
There is a nice vibe usually with people trying to help others on the gcb forum.
Don't be put off by my critisism it was it didn't clarify things like the overflow which is what the topic was about.
How about
A word is 2 bytes. A low byte and a hi byte. It's value can be 0 to 65535. It's value is low byte + 256 * hi byte.
If you increase a word value past 65535 it become 0. This is word overflow.
Similarly, if you decrease a word value below 0 it becomes 65535 ie -1.
So we have a way of using minus word numbers
65535=-1 to 32768=-32767 and +1 to +32767.
Say we have a wordvara and wordvarb
wordvara=1000 : wordvarb=2
wordvara+wordvarb=1002
but suppose you wanted wordvarb to be -2 ie a negative number.
you use wordvarb=not wordvarb+1
This will change 2 into 65534
now wordvala + wordvalb=998 ie it's subtracted 2.
this the overflow in action.
if you want to change the sign of wordvarb back to positive then use
wordvarb=not wordvarb+1 again. 65534 is now 2.
This how to make positive numbers minus numbers and visa versa.
So a way to increase or decrese a word var by adding another word that can be + or - .
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi all. I have a graphic program on a 320x240 x=320.,y=240 display.
I use word values for the x,y position of a space---chr 32.
I use a xdirection and ydirection to move the space. These are word values.
I add the xdirection to xposition and ydirection to yposition to move the space.
if xdirection=4 then it moves 4 pixels right. if xdirection is 65535-4 then it moves -4 pixels left.
You can't define a variable as a minus number in gcb so I'm using the over flow feature.
My question is how to make positive numbers negative number and negative nubers positive without if then.
Where 1234 are plus and 65534,65533,65532,65531 are -1,-2,-3,-4
0 and 65535 seem the same?
I thought but not tested
Many factors... integers support minuse
Negative numbers in Binary are represented by 2's complement notation with the Most significant bit (that is bit 15 in a 16 bit Variable) being the sign bit. However the interpretation of the sign is dependent on the variable type and that is where GCBASIC is a little confusing, as are all languages.
In GCBASIC:
Integer is a 16 bit signed variable with a range of -32768 and 32767
Word is an unsigned 16 bit integer with a range of 0 and 65535
So you should be using Integer not Word if you need 16 bit signed values.
Cheers
Chris
Thanks for replying.
The screen is 320 by 240, I used word values for x,y position and word values for x and y direction.
To change x or y direction from + to - ,or - to + , I just say ball_xdirection=65535-ball_xdirection.
I then say ball_x=ball_x+ball_xdirection.
No if then testing.
Sorry but I thought you were asking a question not making a statement.
If you are happy using an unsigned integer (word) to represent negative values I will leave that to your better judgment.
If you would prefer to do it in a way that others can understand then use signed Integer variables instead of unsigned Word Variables.
For the sake of others reading this thread the correct way to form a 2’s complement (i.e. negate a number in binary) is:
ball_xdirection = 1 + NOT ball_xdirection
This works because a 2's complement number is the Complement of the Number Plus One and the above will work regardless of the variables Bit length so is valid for byte, integer and long variables types.
Cheers
Chris
I'm confused. I thought not was for a bit like port a=!port a. I didn't realise it worked for byte.
but then and or do. Silly me.
"integer is a 16 bit signed variable with a range of -32768 and 32767" I don't understand that.
I though integer was 0-255.
negative numbers are covered where in help?
so dim ball_xdirection as what? it has be word for 16 bit?
how would I define ball_xdirection=-4? would that be 32765 ?
and would 4 be 32770?
I changed ball_xdirection=65535-ball_xdirection to
ball_xdirection=1+not ball_xdirection
and it runs the same!
so I am using a sign word variable?
which method would be fastest and less code memory?
You raise a valid point and one that many computer users forget to explain so I think we need to look at a few basics - pun intended - as you are not alone in your confusion over variables and types. I will break it down into small chunks to try and simplify it for everyone.
It will, however, be a long post though so give me a few minutes / hours to get my thoughts down in text and post it here.
I changed a few start values for ball and bats and found the xdirection dropping to 0.
so changed instances of ball_xdirection=1+not ball_xdirection back to 65535-ball_xdirection and it works.
I have a game in the demos,tron,where I use 255 for-1 and Evan thought it was cool. Not I'm doing it wrong.
Negative numbers needs explaining in help and the bit about U L H is confusing. The help could be improved.
random numbers between a range say 1 to 4 could be explained
random/85+1 ?
it should drop to Zero that is part of the definition of an integer.
All will be explained but as it is nearly Midnight here and I am only halfway through writing the explanation it will have to wait until the morning.
Watch this thread as I try to Integrate your Integers into Words with as few Negatives as possible to Compliment your observations :>)
I'm sort of pleased I worked out 65535-word changes it to a minus number and visa versa if it was negative when added to another word variable.
I couldn't find anything in help to help.
I think it works for byte vars. ie 255-bytevar changes it's sign when added to another bytevar.
"it should drop to Zero that is part of the definition of an integer."
it's supposed to make 4=-4..not reduce it to 0. each time the ball hit a certain condition the xdirection dropped by 1 using 1+not wordvar.
If I'm to make my code more easy for other users to understand then I'm told to use the method suggested as if it was common knowledge. Well it's a shame that "the normal way to use negative numbers that others can understand" isn't mentioned.
So other users won't understand 65535-word changes it's sign?
While on the subject of gcb users knowledge, is goto allowed anymore?
In this program
set up glcd and dim, init vars
start:
do
program
if condition goto start ie goal scored or player 1 or 2 won
loop
I don't want to use goto because it's supposed to be not used but seems a simple way.
I hope my comments don't upset anyone like why doesn't stan get another simpler hobby :)
No
goto
in the Pong game Stan..... keep it structured please.It's not I'm jumping out of a sub and is there a stack of retun addreesses that will overflow.
Structure????
Respect but the program is in line ie no subs. I use multiple if thens instead of logical operator and. It's all about speed so make my code fast as possible eg if the ball is going left then check right bat back and left bat front AND left border and scored goal. Same for ball going right.
Checking top and bottom border is separate and did check left and right border before.
If you're doing games,they must run fast!
If I made the main do loop a sub could I exit it so it went to next command after calling it eg
sub game
other stuff
sub game
do
program
condition=end sub
loop
end sub
?
one goto start would be easiest because when a goal is scored the program reinitialises vars except scores, clears and re- draws screen ie starts again...the initial ball x,y direction being random.
If you can advise me to how to make my code structured without extra code and run at same speed then my ears are on.
I have written programs that sub common code and the main program looks shorter but to see what's happening you have to scroll to the sub to see what's happening.
Structured code seems inefficient...and not easier to read imho :)
Code so far for those interested. I'm open to comments.
If I've dimmed a var then It's value is 0..yes?
so I don't need to define those vars as 0 if they should start at 0?
eg dim var as byte
var=0 ;---not needed?
saves code
I would always set the initial value.
I have had situations where the RAM is not zero.
help says undefined var is zero.
I play safe and give values but if I can save code then I do.
update help again. Can I use a text editor to change help files and submit for whoever's approval? A few more examples maybe in a different stylee? eg this issue.
imho help needs updating. It's good but incomplete and examples seem complicated...cos they're pic. I'm not moaning, just positive thoughts....also as posted negative thoughts :)
-The Positives and Negatives of Variable Types
This is an attempt to clarify the different types and sizes of data variables used by GCBASIC and how they are interpreted or handled by GCBASIC Functions and to give a better Idea of which type to use when. Much of this holds true for any programming language so I will point out a few issues of Code Portability as I go.
Unfortunately it is not possible to do the topic justice without teaching a bit of Computer science theory at the same time but I will attempt to keep it light hearted and not too dry.
Why do we have so many different variable Sizes?
In computer science numbers are represented in Binary and have specific sizes set by the Memory or Register Size and the ALU (Arithmetic Logic Unit) of the device that is acting on the data.
Common sizes are Bit (1 Bit), Nibble (4 Bit), Byte (8 Bit), Word (16 Bit), Long (32 Bit) and Long Long (64 Bit).
GCBASIC has Bit, Byte, Word and Long Variable Types, all of which are described below, but it has no Long Long (64 Bit) type as yet.
Bit is used as a Flag or a Port Pin and has two states ON/OFF - TRUE/FALSE - HIGH/LOW - 1/0 - SET/RESET and many other complementary states Depending on how your application interprets and handles the data.
Byte is the most common variable size in 8 Bit devices and could represent a Number, an ASCII Character, a Port, two Nibbles (Think Hex or BCD), an Internal Register or any user defined collection of Bits such as Flags.
Word is normally used for its Numeric value. 16 Bits will allow it to store Numbers from Zero to 65535 which is large enough to store the product of any two 8 bit Bytes without overflowing. However, it is not confined to being used as a numeric value. It may be used in any manner that your application needs depending on how it interprets the 16 Bits of data. Examples may be a memory address or data pointer.
Note: the Word variable type in GCBASIC, or any other language, has nothing to do with the Word Size of the ALU (Arithmetic and Logic Unit). The Word size of a device (as opposed to the Word Type above) is a representation of the number of Bits that it can manipulate simultaneously in the ALU. The Word Size is generally 4 Bits in older Microprocessors (intel 4004) to 64 Bits in modern computer and 4G devices. The ALU size of the PIC and AVR Microcontrolers supported by GCBASIC are 8 Bits and so they are considered to have an 8 Bit Word.
Long is for situations where Values exceeding 65535 have to be handled and has a range of zero to 4.29 Billion. It is rarely used in 8 Bit devices but is invaluable on the rare occasions that it is needed. The Millis function uses the Long Data Type to handle long time periods
All of the above can be considered to be Integer Values of varying magnitude as they can hold non Fractional Positive Whole Numbers, but try not to confuse Integer Values with the Integer Variable Type, they are complementary but separate concepts as you will see below.
In the real world.............
An integer is a Mathematical Construct that represents a whole number (not a fractional number) that can be Positive, Negative, or Zero. Of itself the Integer is not a computer construct but is a root principal of Mathematics.
In real world applications we also need to be able represent Negative Numbers in our variables and that is where the GCBASIC Integer Variable Type enters the discussion. An Integer Variable is exactly the same as a Word Variable as they are both 16 bits and can store a positive whole number. The difference is not in the Physical storage but rather how the Compiler Interprets the bits that it contains.
The compiler will treat a Word Variable Type as a Variable that can store the values 0 < 65535 but it will see the Integer Variable Type as a Variable that can store values of -32768 < 0 <32767.
In Computer Science the GCBASIC Word Variable type would be called an Unsigned Integer and the otherwise identical Integer Data type would be a Signed Integer.
The modern way to refer to such types is:
Uint16_t for an Unsigned 16 bit Integer Value and Int16_t for a Signed 16 Bit Integer Value.
As you can see that eliminates the conflict between Word Size and the Size of a Word Variable as well as the Definition of an Integer Variable as opposed to a Word Variable both of which are 16 bit values.
One Size does not fit all
A lot of confusion comes from the Type definitions of the chosen language, in this case GCBASIC these are:
All 4 of the above are Integers in that they are representations of a non fractional number:
But they can only represent positive numbers. In Mathematics we need an Integer that can be Positive, Negative, or Zero. Note that Zero is a Positive Whole Number.
To add to the confusion (and hindering code portability) different implementations of C and C++ as well as versions of BASIC, PASCAL, FORTRAN and FORTH all use different sizes of Integer as the default integer size.
They also differ in the declaration of signed vs unsigned Integers.
In order to avoid confusion modern languages now encourage the use of more specific types such as:
And the Unsigned Equivalents
Such descriptive types help when porting and debugging code.
To correlate the GCBASIC variable Type when porting code between Arduino and GCBASIC here is a list of Equivalents that you may use:
There are always Negatives
As noted above, the mathematical definition of an integer also requires that it be able to represent a negative number but the computer has no such concept.
In mathematics, a negative number is a positive number prefixed by a ‘-’ (minus) symbol. So in order to distinguish a negative from a positive number in binary we use a sign Bit. If the Most significant bit is Set (1) the value is negative if it is Clear (zero) the number is positive.
But this simple solution would have repercussions:
There is, however, a simple trick in Binary mathematics called the Two's Complement that overcomes all but the magnitude issue as the Most Significant Bit is still a sign bit.
Two's Complement
To take the Two's Complement of a number it is inverted then incremented:
MyVar = NOT MyVar + 1
The increment has two effects, it avoids the possible creation of a negative zero as a value of 1000000 would be seen as -128 and it allows subtraction to be achieved through addition.
In the above if MyVar contained a value of 1 in an 8 Bit ALU that would be:
00000001
The NOT will make it
11111110
Note that the Most significant Bit is now 1 so the value is negative.
The increment will result in a value of:
11111111
So Minus one using an 8 Bit ALU in Two's Complement notation is 11111111
Let's test it by adding -1 to plus 3
We have successfully subtracted 1 from 3 by adding Minus 1 to 3 and obtaining a result of 2.
And thanks to Computer science we can now answer Shakspear’s centuries old question:
2B OR NOT 2B = -1
Notice that whilst a Byte is normally used to represent 0 < 255 by making the MSB (Most Significant Bit) into a sign bit the maximum value is now 127. A signed 8 Bit integer can represent numbers in the range -128 < 0 < 127. That is still 256 values including Zero but they can now be Negative or Positive numbers.
The benefit of the two's complement method is that it works for any size of variable:
All of the above will result in a Negated version of the original contents.
But not all, in fact relatively few, functions of a Microcontroller require negative values so in situations where negative values are not required the loss of half of the magnitude of a Byte or Word can be significant. That is why it is necessary to be able to specify if a value is Signed or Unsigned, that is if the MSB is the sign bit or part of the value.
It is obviously important from the above that the Program or Functions need to know what sort of data to expect as a value of 0xFF could be considered to be both 255 and -1 depending on the interpretation of the variable. That is why it is important to have Signed and Unsigned Data Types so that the compiler can decide how to handle or interpret the contents. As we saw above in GCBASIC those types are referred to as Integer and Word respectively.
In conclusion ..............
The Negative Number is a Mathematical Construct that can be represented in Microcontrolers as a two’s complement number of arbitrary length. The Microcontroller itself has no concept of Negative numbers and the ALU is not able to perform a subtraction. It subtracts by adding the Two’s Compliment of the value it wants to subtract.
A Two's Complement number can be any bit size, in the case of GCBASIC there is only one Signed Variable Type Defined, that is the Integer Type which is used to hold an Int16_t value. That is a Signed 16 bit Integer with a value range of -32768 < 0 <32767.
There is nothing wrong with treating any variable Type as signed and as seen you can even take the two’s compliment of a Byte and add it to another Byte in order to subtract one byte value from another. But the Maths Functions of GCBASIC are intended to work with Signed 16 bit integers and will fail to compile if you try to use a signed 8 Bit or Signed 32 bit values.
I hope this helps clear things up and, if it is found to be useful, I will refine it further and try to answer any specific questions before placing it in the HELP Documentation.
Cheers
Chris
Last edit: Chris Roper 2019-10-23
An excellent exposition Chris. The HELP would definitely benefit from this.
There are stranger things happening in glcd include with different displys ie out of screen co-ordinates. varying efects depending on screen model and size. Decreasing x,y below zero has different effects. I have a few different glcds because gcb supported them and different results.
ssd1309 it wraps around the screen. ili series it takes a while to wrap around...if it does
remember, GLCD memory or x,y coordinates are handled by the LCD controller. Some controllers wrap the memory others do not. Hence, the difference. Programs may have to handle, or, you can use GLCDOverrunProtection.
Back to word math.
-2 -1 0 1 2
655534 65535 0 1 2
To change a variable sign +- it's 0-var not 65535-var which the compiler accepts and works.
Before 65535-1=-2 now 0-1=65535
and 0-65535=1...well it seems to work in the game. I should print vars on screen.
Please Read the Article that I spent several hours writing for you as it explains Two's Complement arithmetic.
What you are doing is WRONG and I have tried my best to explain why................
Chris-How to dim word or byte as signed please.or is that in help and I missed it?
var=0-var seems to invert it's sign but not printed out results yet.
I'll try changing every instance of var=0-var to var=1+not var and see.
Word type is an Unsigned (Uint16_t) but the Integer type is a Signed (Int16_t) so there no need to dim word as Signed just use Integer instead.
You can't Dim a Byte as Signed in GCBASIC the only signed Type that it recognised is the Integer Variable (Int16_t). But that does not prevent you form using a Byte as if it were signed.
Any variable is just a collection of Bits. The interpretation of the meaning of those bits is entirely up to you. It could be a Character, a Signed Number, and unsigned number etc. The Device you send it too will also trate it in the format it expects signed or unsigned regardless of how it is defined in GCBASIC.
That is because GCBASIC has to convert it to two's Complement in order to perform the subtraction. All you are achieving there is less efficient code.
"var=0-var seems to invert it's sign but not printed out results yet.
"That is because GCBASIC has to convert it to two's Complement in order to perform the subtraction. All you are achieving there is less efficient code."!!!!!!!!!!!!
So the compiler converts 0-var to 1+ not var instead I write 1+not var and the compile accepts that and doesn't convert it?
So although the basic code is longer and using not should be slower in reality the compiler makes it more asm?
Well your way works and I can understand it but did use 0-random/63 as it;s a byte and it can be added to a word. How would you go about adding a minus 8bit random number to a word
As the the topic was about word math then you could have explained better adding a negative word to a word an explaining the overflow.
Again thank you for trying to explain things. It needs explaining in variables help or people like me try to figure it out ourselves...and don't get it right.
There is a nice vibe usually with people trying to help others on the gcb forum.
Don't be put off by my critisism it was it didn't clarify things like the overflow which is what the topic was about.
How about
A word is 2 bytes. A low byte and a hi byte. It's value can be 0 to 65535. It's value is low byte + 256 * hi byte.
If you increase a word value past 65535 it become 0. This is word overflow.
Similarly, if you decrease a word value below 0 it becomes 65535 ie -1.
So we have a way of using minus word numbers
65535=-1 to 32768=-32767 and +1 to +32767.
Say we have a wordvara and wordvarb
wordvara=1000 : wordvarb=2
wordvara+wordvarb=1002
but suppose you wanted wordvarb to be -2 ie a negative number.
you use wordvarb=not wordvarb+1
This will change 2 into 65534
now wordvala + wordvalb=998 ie it's subtracted 2.
this the overflow in action.
if you want to change the sign of wordvarb back to positive then use
wordvarb=not wordvarb+1 again. 65534 is now 2.
This how to make positive numbers minus numbers and visa versa.
So a way to increase or decrese a word var by adding another word that can be + or - .