Signed word and byte arithmetic

matherp

Senior Member
Signed word and byte arithmetic - negative numbers

I got bored with always having to write special case code to deal with negative numbers so have developed a set of subroutines to multiply, divide, MOD, and bintoascii for signed bytes and signed words. Addition and subtraction of course work without any special code. It is interesting that the picaxe interpreter is perfectly happy to allow statements such as w1 = -1234 and correctly implements them.

The code uses a trivial signed version of sertxd for test purposes. Equivalent cut-and-paste routines will also be needed for serout and hserout.

The routine to do bintoascii, which also strips leading zeroes, could also be used and is more general for example to support direct coupled LCD displays

The code should be self-documenting and only bits may be needed in any given program. I have tested reasonably thoroughly but let me have any bugs, questions or comments.

Code:
'
' signed arithmetic
'
' NB add and subtract can be used as normal
' the distinction between + and - is made at the output formatting stage
'

symbol sign =bit0
symbol i = b1
symbol word1 = w1 '-32768 to 32767
symbol byte1 = b2 '-128 to 127
symbol byte2 = b3
symbol word2 = w2 
symbol byte3 = b4 
symbol byte4 = b5
symbol bytearray = 6 'space for using bintoascii, reserve 7 bytes b6-b12
'
symbol positive=0
symbol negative=1
'
' test signed word multiply
'
word1=125
word2= -45 ' This is valid syntax even though picaxe doesn't support negative integers
gosub multsignedword
gosub sertxdsignedword
sertxd(13,10)
'
' test signed word divide
'
word1=-4000
word2=-22
gosub divsignedword
gosub sertxdsignedword
sertxd(13,10)
'
' test signed byte multiply
'
byte1=-10
byte2=-5
gosub multsignedbyte
gosub sertxdsignedbyte
sertxd(13,10)
'
' test signed byte divide
'
byte1=-100
byte2=4
gosub divsignedbyte
gosub sertxdsignedbyte
sertxd(13,10)
'
' test signed word modulus
'
word1=-55
word2=360
gosub modsignedword
gosub sertxdsignedword
'
' test signed byte modulus
'
byte1=-4
byte2=12
gosub modsignedbyte
gosub sertxdsignedbyte
sertxd(13,10)
'
' test signed byte bintoascii
'
byte1=-32
gosub signedbytetoascii
bptr=bytearray
i=@bptrinc
do while i<>0
	sertxd(i)
	i=@bptrinc
loop
'
' test signed word bintoascii
'
word1=-1234
gosub signedwordtoascii
bptr=bytearray
i=@bptrinc
do while i<>0
	sertxd(i)
	i=@bptrinc
loop
do
loop

'Proc sertxdsignedword(word1 As Word)
'
sertxdsignedword:
	If word1 >= $8000 Then
		word1 = -word1
		sertxd( "-", #word1)
	Else
		sertxd (#word1)
	Endif
return                                          
'
'Proc sertxdsignedbyte(byte3 As byte)
'
sertxdsignedbyte:
	If byte1 >= $80 Then
		byte1 = -byte1
		sertxd ("-", #byte1)
	Else
		sertxd (#byte1)
	Endif
return                                          
'
'Function multsignedword(word1 As Word,  word2  As Word) As Word
'multiply word1 by word2 and return the result in word1
'
multsignedword:
	sign = positive
	If word1 >= $8000 Then
		sign = Not sign
		word1 = -word1
	Endif
	If word2 >= $8000 Then
		sign = Not sign
		word2 = -word2
	Endif
	word1 = word1 * word2
	If sign = negative Then
		word1 = -word1
	Endif
return                                      
'
'Function divsignedword(word1 As Word, word2 As Word) As Word
'divide word1 by word2 and return the result in word1
'
divsignedword:
	sign = positive
	If word1 >= $8000 Then
		sign = Not sign
		word1 = -word1
	Endif
	If word2 >= $8000 Then
		sign = Not sign
		word2 = -word2
	Endif
	word1 = word1 / word2
	If sign = negative Then
		word1 = -word1
	Endif
return                                      
'
'Function multsignedbyte(byte1 As byte, byte2 As byte) As byte
'multiply byte1 by byte2 and return the result in byte1
'
multsignedbyte:
	sign = positive
	If byte1 >= $80 Then
		sign = Not sign
		byte1 = -byte1
	Endif
	If byte2 >= $80 Then
		sign = Not sign
		byte2 = -byte2
	Endif
	byte1 = byte1 * byte2
	If sign = negative Then
		byte1 = -byte1
	Endif
return                                      
'
'Function divsignedbyte(byte1 As byte, byte2 As byte) As byte
'divide byte1 by byte2 and return the result in byte1
'
divsignedbyte:
	sign = positive
	If byte1 >= $80 Then
		sign = Not sign
		byte1 = -byte1
	Endif
	If byte2 >= $80 Then
		sign = Not sign
		byte2 = -byte2
	Endif
	byte1 = byte1 / byte2
	If sign = negative Then
		byte1 = -byte1
	Endif
return                                      
'
'Function modsignedbyte(byte1 As byte, byte2 As byte) As byte
'calculate the byte2 modulus of byte1 and return the result in byte1
'useful for clock arithmetic
'
modsignedbyte:
	sign = positive
	If byte1 >= $80 Then
		sign = negative
		byte1= -byte1
	Endif
	byte1 = byte1 // byte2
	If sign = negative Then
		byte1 = -byte1
	Endif
	If byte1 >= $80 Then
		byte1 = byte1 + byte2
	Endif
return                                      
'
'Function modsignedword(word1 As Word, word2 As Word) As Word
'calculate the word2 modulus of word1 and return the result in word1
'useful for degrees arithmetic
'
modsignedword:
	sign = positive
	If word1 >= $8000 Then
		sign = negative
		word1 = -word1
	Endif
	word1 = word1 // word2
	If sign = negative Then
		word1 = -word1
	Endif
	If word1 >= $8000 Then
		word1 = word1 + word2
	Endif
return    
'
'Proc signedbytetoascii
' returns a byte array starting at pointer bytearray terminated by a null
' of the number in byte1
' the number is stripped of leading zeroes
'
signedbytetoascii:
	if byte1>= $80 then
		byte2=$FF
	else
		byte2=0
	endif
'
'Proc signedwordtoascii
' returns a byte array starting at pointer bytearray terminated by a null
' of the numberin word1
' the number is stripped of leading zeroes
'
signedwordtoascii:
	byte3=0
	sign=positive
	bptr = bytearray
	If word1 >= $8000 Then
		sign= negative
		word1 = -word1
	else
	endif
	bintoascii word1,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc
	@bptr=0 'denotes end of string with a null
	bptr = bytearray
	if @bptrinc="0" then ' at least one leading zero
		byte3=1
		if @bptrinc="0" then ' at least two leading zeros
			byte3=2
			if @bptrinc="0" then ' at least three leading zeros
				byte3=3
				if @bptrinc="0" then ' exactly four leading zeros
					byte3=4
				endif
			endif
		endif
	endif
	byte1=bytearray+byte3
	byte2=bytearray+5
	byte4=bytearray
	for i= byte1 to byte2 'now move array (including trailing null) left by the number of leading zeroes
		bptr=i
		byte3=@bptr
		bptr=byte4
		@bptr=byte3
		byte4=byte4+1
	next i
	if sign=negative then
		byte1=bytearray
		byte2=bytearray+5
		for i= byte2 to byte1 step -1 'now move array (including trailing null) left by the number of leading zeroes
			bptr=i
			byte3=@bptrinc
			@bptr=byte3
		next i
		bptr=bytearray
		@bptr="-"		
	endif
return
 
Last edited:

hippy

Technical Support
Staff member
Excellent stuff. Just a couple of tips that may be useful -

If word1 > 32767 Then

Could perhaps be better written as ...

If word1 >= $8000 Then

As that IMO more obviously indicates that the decision is based upon the msb being set, >= $80 for bytes.

word1 = 0 - word1

Can simply be written as ...

word1 = - word1
 

BESQUEUT

Senior Member
Do you know that :
-125 is 65411
-45 is 65491
Then -125*-45= 4283831801

4283831801 MOD 65536 is .... 5625

Multiplication of negative number is perfectly functional with simulator. (Not tested with real Picaxe)
No need for a subroutine ?
 
Last edited:

BESQUEUT

Senior Member
Just tested with Picaxe 40X2, and I can confirm :
multsignedword
multsignedbyte
are useless because Picaxe is perfectly able to multiply signed words and signed bytes.

Of course, others subroutines (divide, modulus and sertxd are necessary).

Code:
word1=125
word2= -45 
word1=word1*word2
sertxd(13,10,"125 * -45=")
gosub sertxdsignedword
sertxd(13,10)

'
word1=-125
word2= -45
word1=word1*word2
sertxd("-125 * -45=")
gosub sertxdsignedword
sertxd(13,10)





'
' test signed word divide
'
word1=-4000
word2=-22
word1=word1/word2
sertxd("-4000 / -22=")
gosub sertxdsignedword
sertxd(13,10)
'
' test signed byte multiply
'
byte1=-10
byte2=-5
byte1=byte1*byte2
sertxd("-10 * -5=")
gosub sertxdsignedbyte
sertxd(13,10)
'
' test signed byte divide
'
byte1=-100
byte2=4
byte1=byte1/byte2
sertxd("-100/4=")
gosub sertxdsignedbyte
sertxd(13,10)
125 * -45=-5625
-125 * -45=5625
-4000 / -22=0
-10 * -5=50
-100/4=39
 
Top