16bit maths help

jon_nic

New Member
Hi
I am using a 14M2 and need to multiply a Word variable by 105 decimal. I then need the answer in a format i can use for display on an LCD/OLED. this is easy if the variable value is less than 624 decimal, as the maths result is less than the overflow of 65,020. but the word variable can be upto 1023 decimal in value, so obviously it overdflows. I have tried ** but it didnt give what i want.

once the maths is done, i want to be able to convert to Ascii with "bintoasci" and display the full number on screen
example, 105 x 1011 = 106155 which cant be done with word *word maths. What i would like is for a word to hold the MSB of the sum "106" and another Word to store "155" then i can easily put them to ascii and send to screen.


whats the best way for this?
 

geoff07

Senior Member
I don't know about 'best' but one way would be to do the calculation longhand in decimal. By which I mean simulate the way you would do it on paper, using a byte for each digit (or two digits if you used bcd), and multiplying each digit at a time, adding together each partial result to make the total. It would be relatively slow and use up some code space, but the limits on number size would be determined by you, and the result could easily be displayed.
 

AllyCat

Senior Member
Hi jon,

Yes, I can think of at least three ways to do the calculation, but am not sure which would be "best" for me, let alone for you. It's not possible to simply use bintoascii because that "expects" to receive a single word (16 bits) and create five ASCII characters (i.e. digits), which might include leading zeros. Typically, you need to repeatedly divide by 10, creating the number by displaying the remainders (in reverse order).

The second code snippet that I posted here can do the task, but is certainly "overkill" for your application (slow and unnecessarily complex code).

The method suggested by geoff is probably the method that I would use. The basic idea was discussed from about post #13 in this thread.

Or for your specific calculation, which produces a result only slightly larger than a single word (i.e. 17 bits), it might be easiest to write some "custom" code: The "high word" (i.e. the result of 105 ** w1, where w1 < 1024) can be only '0' or '1'. If it is '0' then you can just use bintoascii on the result of 105 * w1 (adding a leading zero if required).

If the high word is '1', then the value in the result of 105 * w1 has overflowed, so it is 65,536 too small. Then you could use bintoascii and correct the values with a few lines of code such as the following (incomplete and untested) :

Code:
; If high word is 1 then add 65536
bintoascii w1,b15,b14,b13,b12,b11 
b11 = b11 + 6			; Update the Units digit
if b11 > "9" then
	b11 = b11 - 10
	inc b12			; Carry to the Tens digit
endif
b12 = b12 + 3			; Update the Tens digit
;    etc....
Note the quotes " " to specify the comparison of ASCII digits

Cheers, Alan.
 

Armp

Senior Member
If the high word is '1', then the value in the result of 105 * w1 has overflowed, so it is 65,536 too small.
Suggest:
Code:
; If high word is 1 then make the high word (thousands) = 65, and add 536 to the low word
IF HighW=1 then 
  HighW=65
  LowW=LowW+536
Endif
 
HighW=LowW/1000+HighW  ;Add Thousands from low word
LowW=LowW//1000        ;Keep Remainder in low word
;then bin2ascii etc
 

westaust55

Moderator
For your current specific case you can try this
Which should work with a value from 0 to 1048 and a multiplier of 105
Code:
; valid for a variable with a value up to 1248
; for W5 could get away with a byte variable instead
W4 =variable * 105  ; low word = b9:b8
W5 = variable ** 105*6  ; high word  = b11:b10
IF W5 = 6 THEN : W4 = W4 + 5536 : ENDIF
W5 = W4 / 10000 +W5
W4 = w4 // 10000
; use BINTOASCII for W5 value and keep lowest/right most two digits as 100-thousands and 10-thoussands
; use BINTOASCII for W4 value for the lower 4 digits
; output/display your 6 digits
 

marks

Senior Member
Hi jon_nic,
keeping it simple you can usually get an extra digit

w0=1011 'simulate adcValue 1011

w2=w0*21/2 '10615
w1=w0//10*5//10 '5
sertxd(#w2,#w1)
 

jon_nic

New Member
Hi jon_nic,
keeping it simple you can usually get an extra digit

w0=1011 'simulate adcValue 1011

w2=w0*21/2 '10615
w1=w0//10*5//10 '5
sertxd(#w2,#w1)


thanks Marks, and everyone else for their code ideas. Marks simple *21/2 (equivelent to *10.5) would work great as i can ignore the least signifiancant numbers i only need the most significant 5.
 
Top