Often times a value stored somewhere may not be the same width as an MMBasic Integer variable, being commonly 8, 9 or 16 bits wide. For example, the temperature register (&H11) of the popular DS3231 RTC chip is a two's-compliment byte. Reading (theoretically) +127 to -128C.
If this number is placed directly in an integer variable without sign extending bit 7 through to the end of the integer (bit 63) the temperature will be incorrect if negative - it will read over 128C. It is necessary to extend bit 7 of the register through the remaining 56 bits to obtain a true 64-bit integer value of the reading that will play nicely with integer maths... Of course this isn't necessary if you are not expecting sub-zero temperatures and are OK with taking the chance.
The following function will return a value sign-extended from any given bit. There is no error checking - if you feed it rubbish or try to crash it you'll probably succeed.
Syntax:=SgnX(Bit,Value)
Examples: (better understood looking at the binary)
Print Bin$(SgnX(7,&h7f),64)
0000000000000000000000000000000000000000000000000000000001111111
^ bit 7
Print Bin$(SgnX(7,&h8f),64)
1111111111111111111111111111111111111111111111111111111110001111
^ bit 7
Consider the following:
RTC GetReg 17,x
Here x contains the 8-bit, two's compliment value for the temperature but as the remaining (top) 56 bits of x are zero, the value will always be treated as positive by MMBasic. Imagine the value read was 254 (&hFE), which is -2 degrees (bit 7 is set). When assigned to the variable x, it will be treated as the absolute value of the register - positive 254 (bit 63 is 0 = positive, and all the bits in between).
Print Bin$(x,64)
0000000000000000000000000000000000000000000000000000000011111110
To correct this, the sign of the register value (bit 7) needs to be extended through (copied-to) the remaining 56 bits up to bit 63 which then makes the integer variable x hold the equivalent 64 bit version of the value:
x=SgnX(7,x)
Print Bin$(x,64)
1111111111111111111111111111111111111111111111111111111111111110
Print x
-2
As another example, if a value read is 9 bits (maybe from serial comms) which is to be interpreted as two's compliment 8 bits for the value plus sign bit, simply extend bit 9, or for a traditional 16 bit signed integer, extend bit 15. The function will take any bit as the sign and return a correctly formatted 8 byte MMbasic integer.
Code:
Function SgnX(b As Integer,v As Integer) As Integer' sign extend bit b of value v
If v And 2^b Then 'extend 1
SgnX=v Or (-1 << (b+1))
Else 'extend 0
SgnX= v And ((2^(b+1))-1)
EndIf
End Function