 PICMicrocontollerBasicMathMethods

32-bit signed integer math routines. add, subtract, multiply, divide, round, sqrt, bin2dec, dec2bin. By Peter Hemsley.

Also, there is a stack based version that implements add, subtract, multiply, and divide in a FORTH like stack based system

32-BIT SIGNED INTEGER MATHS FOR PICS

Maths routines for computers, microprocessors and microcontrollers are nothing new. They have been around almost since the invention of the computer, but finding a comprehensive set of routines can be difficult. If you do not have the ability to write your own routines then you must rely on someone else's work. It may be poorly written or incomprehensible due to lack of documentation ,which is often the author's experience. The purpose of this article is to explain how various maths functions are performed and to present a complete 32-bit maths package which can handle huge numbers, and yet not take too much precious memory space. The routines presented here are: Add, Subtract, Multiply, Divide, Round (for divide), Square Root, Binary to Decimal, and Decimal to Binary conversion.

MULTIPLE PRECISION

An 8-bit register or memory is able to store numbers in the range 0 to 255. If two 8-bit numbers are added together it is quite possible that the sum will exceed 255, so how do we cope with larger numbers? The answer is to use more bits. Imagine a 16-bit register (or memory), this is able to hold numbers up to 65535. You can add numbers to this register many times so long as the total does not exceed 65535. Now split the 16-bit register down the middle into two 8-bit sections. This does not change the nature of the number it contains, but each section can now be stored in adjacent 8-bit (byte) memory locations. The two bytes are usually  referred to as High byte and Low Byte.  Of course the PIC cannot add 16-bit numbers directly, you  must program it to add each byte separately and deal with any overflow from one byte to the next. If you need numbers larger than 65535 this concept can be extended to 24 bits using three bytes for the number, or 32 bits using four bytes. The name given to this  is Multiple Precision Numbers.

TWO'S COMPLIMENT

General purpose maths routines should be able to cope with negative numbers as well as positive ones. Two's compliment is one of several method for representing both positive and negative numbers. It is a logical extension of unipolar (positive) numbers, which makes it the most widely used method. Other methods such as signed magnitude and offset (also known as biased) are to be found in floating point format numbers and are beyond the scope of this article. A disadvantage of two's compliment is that it works only for addition and subtraction, for other functions the result sign must first be calculated and the numbers made positive before calculating the result.

First we shall look at how two's complement numbers are derived. If an 8-bit register contains a value of  0, when 1 is subtracted from it the result will be FF. Logically this is -1. If 2 is subtracted from 0 the result is FE which is -2, FD is -3 and so on. With an 8-bit register it is possible to represent a numeric range of -128 to +127. For a 16-bit register, -1 = FFFF, -2 = FFFE, -3 = FFFD etc with a range of -32768 to +32767. This concept can be extended to any number of bits you wish although 32 bits is usually considered to be enough. This equates to a  numerical range of -2,147,483,648 to +2,147,483,647. The term "Two's compliment" is derived from the method used to  negate a number, i.e. change it’s sign from positive to negative or vice versa. To do this first invert all the bits of the number, this is known as one's compliment, and then add 1 to the number to obtain the two's compliment.

Where a number is more than 8 bits (one byte) long several consecutive bytes are used to store the number, this is called Multiple Precision. It is normally easy enough to add two multiple precision numbers, but the RISC instruction set of the PIC does not allow for carrying any overflow from addition into the next byte. In the author’s experience there often appears to be some confusion of how to do this. Listing 1 shows the correct method of adding two multiple precision  numbers, NUM1 and NUM2. The L, M and H at the end of the variable names refer to Low, Middle and High bytes respectively. The Carry will be correctly set on exit, indicating any overflow from the addition. Subtraction is performed in a similar manner. Another way of subtracting a number is to first negate it (two’s complement) then perform an addition. This eliminates the need for a separate subtraction routine. The arithmetic unit of microprocessors, including PICs, use two’s complement to perform subtractions.

Listing1

skpnc               ;No carry_in, so just add
incfsz  NUM2M,W     ;Add carry_in to NUM2
skpnc               ;No carry_in, so just add
incfsz  NUM2H,W     ;Add carry_in to NUM2
…

MULTPLICATION

You can perform binary multiplication in the same way that you do decimal long multiplication by hand. Before going into detail we will look at a worked example of multiplying 13 by 10, in binary that is 1101 and 1010.

1101   (multiplicand)

x1010   (multiplier)

0000   (partial products)

1101

0000

1101

10000010    (product)

Starting with the least significant digit of the multiplier, multiply the multiplicand by each multiplier digit in turn and write the results (partial products) below. Ensure the rightmost digit of each partial product lines up with it’s generating digit in the multiplier. Keep going until you run out of digits in the multiplier. Now add all the partial products together and you have the final result. A quick check of the result confirms it is correct. 128 + 2 = 130.

Now we shall look at how to write a multiply routine in assembler. Since the numbers are binary no multiplication is actually needed because multiplying by zero gives zero as a result, and multiplying by one produces the same number you started with. This just leaves the problem of whether to multiply by 0 or 1. To do this each bit of the multiplicand is shifted into the Carry for testing. If the bit is a 1 then the multiplier (or more correctly, the multiplier times one)  is added to the partial product , if the bit is a 0 then nothing is done since there is no point in adding zero to the partial product. The final task is to ensure the bits are correctly aligned at each addition, this is simply achieved by shifting the partial product in line with the multiplicand.

Listing 2 shows a simplified 8-bit x 8-bit multiply. The variables MPCAND and MPLIER are multiplied to give a 16-bit result in PRODH and PRODL. There are numerous variations of this routine. It is also possible to work from left to right, starting with the most significant digit and shifting left. The best method to choose depends on the processor for which it is written, the number of bits and the programmer’s personal preference.

Listing 2

mult            clrf    PRODL,F              ;Clear result
clrf    PRODH,F
movlw   0x08                 ;Bit
counter
movwf   COUNT
movf    MPCAND,W             ;Multiplicand in W reg
loop            rrf     MPLIER,F             ;Lsb into Carry
skpnc                                     ;Test Carry
rrf     PRODH,F              ;Align result
rrf     PRODL,F
decfsz  COUNT,F              ;Next bit
goto    loop

…

DIVISION

You will probably not be surprised to learn that division is pretty much the reverse of multiplication . Binary division can also be performed in the same way that you do decimal long division by hand, and  again because the numbers are binary no division is actually needed. Where multiplication uses successive shifts and addition, division is done by successive shifts and subtraction.

An example of long division in binary is shown below. Those who are familiar with decimal long division should have no problem with the format, although it has been expanded somewhat for clarity. It shows 15 divided by 3.

0101            (quotient 5 )

0011 ) 1111          (divisor 3 )dividend 15 )

1                   (partial remainders)

11

-11                (subtract divisor)

0

01

011

-011            (subtract divisor)

0             (remainder)

The most significant digit of the dividend is put into the partial remainder and compared with the divisor. If  the partial remainder is less than the divisor then the quotient digit is a 0. If the partial remainder is equal to or greater than the divisor, the quotient digit is a 1, the divisor is subtracted and the remainder written below. The next dividend digit is now appended to the new partial remainder and the comparison is repeated until all the dividend digits have been processed. The partial remainder must always remain less than 2 times the divisor, for this reason division is not needed for binary numbers. Unless, of course, you insist that dividing by 1 is a valid argument.

In this example the division is exact i.e. the result is an exact integer. If, for example, 14 were divided by 3 the result would be 4 with a remainder of 2 on the bottom line. Integer division always rounds down to the nearest whole number unless extra code is written to provide rounding up the result if the remainder is 0.5 or more.

Converting the division procedure into an assembler routine is very easy. Listing 3 shows a simple 8-bit by 8-bit divide. Appending to the remainder is done by shifting the msb of the dividend into the Carry and then into the lsb of the remainder. Because of their RISC instruction set PICs do not have a compare instruction so subtract is used to compare the values of the remainder and divisor, the result of the subtraction being held in the W register. Setting the quotient bit is done by shifting in the Carry which was cleared or set by the subtraction.

Listing 3

divide          clrf    QUOT                   ;Clear quotient
clrf    REM                    ;Clear remainder
movlw   0x08                   ;Bit count
movwf   COUNT
loop            rlf     DIVID,F                ;Shift dividend bit
rlf     REM,F                  ;into remainder
movf    DIVIS,W                ;Trial subtraction
subwf   REM,W
skpnc
movwf   REM                    ;Subtraction was ok
rlf     QUOT,F                 ;Carry is result bit
decfsz  COUNT,F                ;Next
bit
goto    loop
…

ROUND

As previously mentioned result of division is rounded down, or more correctly truncated, if the result is not an exact integer. We can obtain a more accurate result by rounding up or down to the nearest integer when there is a fractional part to the result. This routine adds 1 to the result if the remainder of the division is 0.1 binary or greater, which is equivalent to 0.5 decimal. This helps to minimise errors caused by multiple uses of division.

SQUARE ROOT

You can square a number simply by multiplying it by itself, square rooting a number is a little more difficult. There are many ways to find the square root of a number, probably the best method for large numbers was described by the same author in the August 2002 issue of EPE. It is very similar to division since the square root of a number is equal to the number divided by it’s square root. The original 24-bit routine has now been expanded to 32-bit.

GETTING IT IN AND OUT

You would like to see the results of all your calculations and would like it to be in decimal, similarly you want to input numbers in decimal. This makes Binary to Decimal and Decimal to Binary routines an essential part of any maths package. Many assembler programmers will at some time have attempted these conversions, usually in a crude fashion. (As were the author’s attempts many years ago) . These methods such as subtracting the binary equivalent of powers of ten are perfectly valid and can be useful, but when it comes to very large numbers there are much better methods available. The Binary to Decimal and Decimal to Binary routines presented here complement each other, they both use the same method but each is the reverse of the other. The method chosen for this package is simplicity itself and very flexible. The routine is compact and easily modified for various bit lengths. A simplified  version is shown in Listing 4. The most significant bit of BINARY is shifted into the least significant digit, ONES. If the digit has a value of 10 or more then 10 is subtracted from it and 1 is added to the next higher digit. The Carry is used to add 1 to the next digit as it will be set by the subtraction if the digit is greater than 9. The rest of the digits are shifted  and checked in a similar manner and the whole process repeated until all the bits of the binary number have been shifted out of BINARY and into the digits. The hundreds digit is not tested in this instance since it cannot overflow as the maximum decimal value for 8-bit binary is 255.

Decimal to Binary consists of the same procedure but doing it all in reverse. Shifting bits through the digits and into the Carry, adding 10 to the digits when necessary and shifting the Carry into the binary.

Listing 4

clrf    ONES
clrf    TENS
clrf    HUND
movlw   8                       ;Bit count
movwf   BCOUNT
loop            rlf     BINARY,F                ;Shift msb into
rlf     ONES,F                  ;first digit
movlw   10                      ;Digit > 9 ?
subwf   ONES,W
skpnc
movwf   ONES                    ;Digit = digit -10
rlf     TENS,F                  ;Shift carry in
movlw   10                      ;Digit > 9 ?
subwf   TENS,W
skpnc
movwf   TENS                    ;Digit = digit -10
rlf     HUND,F                  ;Shift carry in
decfsz  BCOUNT,F                ;Next
bit
goto    loop

USING THE 32-BIT ROUTINES

Signed 32-bit numbers have a range of -2147483648 to +2147483647. However -2147483648 does not have a positive equivalent which would needed in many cases and so the range is limited to ± 2147483647, with -2147483648 being trapped as an error. Three 32-bit pseudo-registers are defined, REGA contains the first operand, REGB contains the second operand and REGC is used as temporary storage by the routines. The result is always returned in REGA. Each pseudo-register consists of 4 consecutive bytes denoted by 0, 1, 2 and 3. 0 is the least significant byte and 3 is the most significant byte. High level languages have built-in run-time error checking but assembler has no such luxuries and the programmer must write his/her own. Comprehensive error checking is included in the routines and the Carry will be set on return from the routines if an error is found. The code required  for error checking after calling a routine is shown below.

CALL     <function>

SKPNC

GOTO    <errorhandler>

Because the PICs stack cannot be manipulated errors would usually need to be passed back to the top-most level of the program. Most errors will be caused by an overflow, i.e. the result is greater than 32 bits. When an error is encountered the result returned in REGA will be meaningless. Checking the Carry after calling a routine is optional so long as you are sure no error will occur.

The header of each routine gives a brief description of it’s function and usage. The five basic arithmetic functions are given below for reference.

Add:                       REGA = REGA + REGB

Subtract:               REGA = REGA - REGB

Multiply:               REGA = REGA x REGB

Divide:                   REGA = REGA / REGB

Sq Root:                                REGA = SQRT (REGA)

Note that multiplying two 32-bit numbers can produce a result of up to 64 bits. A limit on the number of bits has to be drawn somewhere and it is 32, so an error will be returned if the result exceeds the 32 bits of REGA.

The Round routine is intended to be called only after division, it will not round the result of Square Root. Only the simplest of rounding is used since it was considered unnecessary to use a more complex method. Check for division error (if needed) before calling this routine.

The Decimal to Binary routine was designed for flexibility and keypad input in mind. It accepts a variable length BCD string of digits. Your input routine should put the first ( most significant) digit entered in the variable DIGIT1, the next digit into DIGIT2 and so on up to a maximum of 10 digits. A count of the number of digits entered must be kept and loaded into the W register before the routine is called. The reason for this is that people are unlikely to include leading zeros when entering a number to make up the full 10 digits that would otherwise be required, it seems leading zero suppression is in human nature. If your digits are in ASCII text format they should first be converted to BCD format by subtracting 48. It is also worthwhile checking that the digits are in the range of 0 to 9 to avoid the possibility of obtaining a meaningless result. The routine also requires a sign bit to indicate whether the number is positive or negative. This is held in the variable DSIGN which should be set to 0 for a positive number or 1 for  negative.

Binary to Decimal requires little in the way of explanation. DSIGN is again used to indicate a positive or negative number. You may use this to precede the number with  a “+” or “-” in your output routine. No output formatting is included as this will be dependant upon the application.

The routines are contained in the file Maths32.txt and are intended to be opened with a text editor such as Notepad and then copied and pasted into your assembly program. You copy all the routines or just the ones you require. But do not forget to also copy the utility routines, most of which will be required. The variable declarations will also need to be copied and you will need supply a start address for them.

The variables require 26 contiguous bytes of data memory but if you do not have this amount available they may be split. Only the variables DIGIT1 to DIGIT10 are required to be contiguous.

Code:

• ;*** SIGNED 32-BIT INTEGER MATHS ROUTINES FOR PIC16 SERIES BY PETER HEMSLEY ***
;
;Functions:
;	subtract
;	multiply
;	divide
;	round
;	sqrt
;	bin2dec
;	dec2bin

;Variable declarations

mathram	equ	;(insert required ram address here)

cblock mathram
REGA0				;lsb
REGA1
REGA2
REGA3				;msb

REGB0				;lsb
REGB1
REGB2
REGB3				;msb

REGC0				;lsb
REGC1
REGC2
REGC3				;msb

DSIGN				;Digit Sign. 0=positive,1=negative
DIGIT1				;MSD
DIGIT2
DIGIT3
DIGIT4
DIGIT5				;Decimal (BCD) digits
DIGIT6
DIGIT7
DIGIT8
DIGIT9
DIGIT10				;LSD

MTEMP
MCOUNT
DCOUNT
endc

;*** 32 BIT SIGNED SUTRACT ***
;REGA - REGB -> REGA
;Return carry set if overflow

subtract
call	negateb		;Negate REGB
skpnc
return			;Overflow

;*** 32 BIT SIGNED ADD ***
;REGA + REGB -> REGA
;Return carry set if overflow

xorwf	REGB3,w
movwf	MTEMP

clrc			;Check signs
movf	REGB3,w		;If signs are same
xorwf	REGA3,w		;so must result sign
btfss	MTEMP,7		;else overflow
return

;*** 32 BIT SIGNED MULTIPLY ***
;REGA * REGB -> REGA
;Return carry set if overflow

multiply
clrf	MTEMP		;Reset sign flag
call	absa		;Make REGA positive
skpc
call	absb		;Make REGB positive
skpnc
return			;Overflow

call	movac		;Move REGA to REGC
call	clra		;Clear product

movlw	D'31'		;Loop counter
movwf	MCOUNT

muloop	call	slac		;Shift left product and multiplicand

rlf	REGC3,w		;Test MSB of multiplicand
skpnc			;If multiplicand bit is a 1 then

skpc			;Check for overflow
rlf	REGA3,w
skpnc
return

decfsz	MCOUNT,f	;Next
goto	muloop

btfsc	MTEMP,0		;Check result sign
call	negatea		;Negative
return

;*** 32 BIT SIGNED DIVIDE ***
;REGA / REGB -> REGA
;Remainder in REGC
;Return carry set if overflow or division by zero

divide	clrf	MTEMP		;Reset sign flag
movf	REGB0,w		;Trap division by zero
iorwf	REGB1,w
iorwf	REGB2,w
iorwf	REGB3,w
sublw	0
skpc
call	absa		;Make dividend (REGA) positive
skpc
call	absb		;Make divisor (REGB) positive
skpnc
return			;Overflow

clrf	REGC0		;Clear remainder
clrf	REGC1
clrf	REGC2
clrf	REGC3
call	slac		;Purge sign bit

movlw	D'31'		;Loop counter
movwf	MCOUNT

dvloop	call	slac		;Shift dividend (REGA) msb into remainder (REGC)

movf	REGB3,w		;Test if remainder (REGC) >= divisor (REGB)
subwf	REGC3,w
skpz
goto	dtstgt
movf	REGB2,w
subwf	REGC2,w
skpz
goto	dtstgt
movf	REGB1,w
subwf	REGC1,w
skpz
goto	dtstgt
movf	REGB0,w
subwf	REGC0,w
dtstgt	skpc			;Carry set if remainder >= divisor
goto	dremlt

movf	REGB0,w		;Subtract divisor (REGB) from remainder (REGC)
subwf	REGC0,f
movf	REGB1,w
skpc
incfsz	REGB1,w
subwf	REGC1,f
movf	REGB2,w
skpc
incfsz	REGB2,w
subwf	REGC2,f
movf	REGB3,w
skpc
incfsz	REGB3,w
subwf	REGC3,f
clrc
bsf	REGA0,0		;Set quotient bit

dremlt	decfsz	MCOUNT,f	;Next
goto	dvloop

btfsc	MTEMP,0		;Check result sign
call	negatea		;Negative
return

;*** ROUND RESULT OF DIVISION TO NEAREST INTEGER ***

round	clrf	MTEMP		;Reset sign flag
call	absa		;Make positive
clrc
call	slc		;Multiply remainder by 2
movf	REGB3,w		;Test if remainder (REGC) >= divisor (REGB)
subwf	REGC3,w
skpz
goto	rtstgt
movf	REGB2,w
subwf	REGC2,w
skpz
goto	dtstgt
movf	REGB1,w
subwf	REGC1,w
skpz
goto	rtstgt
movf	REGB0,w
subwf	REGC0,w
rtstgt	skpc			;Carry set if remainder >= divisor
goto	rremlt
incfsz	REGA0,f		;Add 1 to quotient
goto	rremlt
incfsz	REGA1,f
goto	rremlt
incfsz	REGA2,f
goto	rremlt
incf	REGA3,f
skpnz
return			;Overflow,return carry set
rremlt	btfsc	MTEMP,0		;Restore sign
call	negatea
return

;*** 32 BIT SQUARE ROOT ***
;sqrt(REGA) -> REGA
;Return carry set if negative

sqrt	rlf	REGA3,w		;Trap negative values
skpnc
return

call	movac		;Move REGA to REGC
call	clrba		;Clear remainder (REGB) and root (REGA)

movlw	D'16'		;Loop counter
movwf	MCOUNT

sqloop	rlf	REGC0,f		;Shift two msb's
rlf	REGC1,f		;into remainder
rlf	REGC2,f
rlf	REGC3,f
rlf	REGB0,f
rlf	REGB1,f
rlf	REGB2,f
rlf	REGC0,f
rlf	REGC1,f
rlf	REGC2,f
rlf	REGC3,f
rlf	REGB0,f
rlf	REGB1,f
rlf	REGB2,f

rlf	REGA0,f		;Align root
rlf	REGA1,f
rlf	REGA2,f

movf	REGA2,w		;Test if remdr (REGB) >= root (REGA)
subwf	REGB2,w
skpz
goto	ststgt
movf	REGA1,w
subwf	REGB1,w
skpz
goto	ststgt
movf	REGA0,w
subwf	REGB0,w
ststgt	skpc			;Carry set if remdr >= root
goto	sremlt

movf	REGA0,w		;Subtract root (REGA) from remdr (REGB)
subwf	REGB0,f
movf	REGA1,w
skpc
incfsz	REGA1,w
subwf	REGB1,f
movf	REGA2,w
skpc
incfsz	REGA2,w
subwf	REGB2,f
bsf	REGA0,1		;Set current root bit

sremlt	bcf	REGA0,0		;Clear test bit
decfsz	MCOUNT,f	;Next
goto	sqloop

clrc
rrf	REGA1,f
rrf	REGA0,f
return

;*** 32 BIT SIGNED BINARY TO DECIMAL ***
;REGA -> DIGITS 1 (MSD) TO 10 (LSD) & DSIGN
;DSIGN = 0 if REGA is positive, 1 if negative
;Return carry set if overflow
;Uses FSR register

bin2dec	clrf	MTEMP		;Reset sign flag
call	absa		;Make REGA positive
skpnc
return			;Overflow

call	clrdig		;Clear all digits

movlw	D'32'		;Loop counter
movwf	MCOUNT

b2dloop	rlf	REGA0,f		;Shift msb into carry
rlf	REGA1,f
rlf	REGA2,f
rlf	REGA3,f

movlw	DIGIT10
movwf	FSR		;Pointer to digits
movlw	D'10'		;10 digits to do
movwf	DCOUNT

adjlp	rlf	INDF,f		;Shift digit and carry 1 bit left
movlw	D'10'
subwf	INDF,w		;Check and adjust for decimal overflow
skpnc
movwf	INDF

decf	FSR,f		;Next digit
decfsz	DCOUNT,f

decfsz	MCOUNT,f	;Next bit
goto	b2dloop

btfsc	MTEMP,0		;Check sign
bsf	DSIGN,0		;Negative
clrc
return

;*** 32 BIT SIGNED DECIMAL TO BINARY ***
;Decimal DIGIT1 thro DIGIT(X) & DSIGN -> REGA
;Set DSIGN = 0 for positive, DSIGN = 1 for negative values
;Most significant digit in DIGIT1
;Enter this routine with digit count in w register
;Return carry set if overflow
;Uses FSR register

dec2bin	movwf	MTEMP		;Save digit count

movlw	D'32'		;Outer bit loop counter
movwf	MCOUNT

d2blp1	movlw	DIGIT1-1	;Set up pointer to MSD
movwf	FSR
movf	MTEMP,w		;Inner digit loop counter
movwf	DCOUNT

movlw	D'10'
clrc			;Bring in '0' bit into MSD

d2blp2	incf	FSR,f
skpnc
rrf	INDF,f		;Shift out LSB of digit

decfsz	DCOUNT,f	;Next L.S. Digit
goto	d2blp2

rrf	REGA3,f		;Shift in carry from digits
rrf	REGA2,f
rrf	REGA1,f
rrf	REGA0,f

decfsz	MCOUNT,f	;Next bit
goto	d2blp1

movf	INDF,w		;Check for overflow
skpc
rlf	REGA3,w
skpnc
return

btfsc	DSIGN,0		;Check result sign
call	negatea		;Negative
return

;UTILITY ROUTINES

skpnc			;No carry_in, so just add
incfsz	REGB1,w		;Add carry_in to REGB

skpnc
incfsz	REGB2,w

skpnc
incfsz	REGB3,w
return

;Move REGA to REGC
;Used by multiply, sqrt

movac	movf	REGA0,w
movwf	REGC0
movf	REGA1,w
movwf	REGC1
movf	REGA2,w
movwf	REGC2
movf	REGA3,w
movwf	REGC3
return

;Clear REGB and REGA
;Used by sqrt

clrba	clrf	REGB0
clrf	REGB1
clrf	REGB2
clrf	REGB3

;Clear REGA
;Used by multiply, sqrt

clra	clrf	REGA0
clrf	REGA1
clrf	REGA2
clrf	REGA3
return

;Check sign of REGA and convert negative to positive
;Used by multiply, divide, bin2dec, round

absa	rlf	REGA3,w
skpc
return			;Positive

;Negate REGA
;Used by absa, multiply, divide, bin2dec, dec2bin, round

andlw	0x80

comf	REGA0,f		;2's complement
comf	REGA1,f
comf	REGA2,f
comf	REGA3,f
incfsz	REGA0,f
goto	nega1
incfsz	REGA1,f
goto	nega1
incfsz	REGA2,f
goto	nega1
incf	REGA3,f
nega1
incf	MTEMP,f		;flip sign flag
addwf	REGA3,w		;Return carry set if -2147483648
return

;Check sign of REGB and convert negative to positive
;Used by multiply, divide

absb	rlf	REGB3,w
skpc
return			;Positive

;Negate REGB
;Used by absb, subtract, multiply, divide

andlw	0x80

comf	REGB0,f		;2's complement
comf	REGB1,f
comf	REGB2,f
comf	REGB3,f
incfsz	REGB0,f
goto	negb1
incfsz	REGB1,f
goto	negb1
incfsz	REGB2,f
goto	negb1
incf	REGB3,f
negb1
incf	MTEMP,f		;flip sign flag
addwf	REGB3,w		;Return carry set if -2147483648
return

;Shift left REGA and REGC
;Used by multiply, divide, round

slac	rlf	REGA0,f
rlf	REGA1,f
rlf	REGA2,f
rlf	REGA3,f
slc	rlf	REGC0,f
rlf	REGC1,f
rlf	REGC2,f
rlf	REGC3,f
return

;Set all digits to 0
;Used by bin2dec

clrdig	clrf	DSIGN
clrf	DIGIT1
clrf	DIGIT2
clrf	DIGIT3
clrf	DIGIT4
clrf	DIGIT5
clrf	DIGIT6
clrf	DIGIT7
clrf	DIGIT8
clrf	DIGIT9
clrf	DIGIT10
return

+

Questions:

I'd like to use this 32bit math routines, but dec2bin does not perform well. After my trial, I have found the problem in this coding. Perhaps I have to change the coding as follow.
dec2bin
movlw  D'32'
movwf  MCOUNT
d2blp1
movlw  DIGIT-1
movwf  FSR
movlw  D'10'     ;here MTEMP => D'10'
movwf  DCOUNT
so..on

Mhrikatsu Horino

• Anders W Gustafsson of Pedago Interaktiv Ab asks: " Excellent documentation! But I cannot get bin2dec to work? No matter what I do I end up with zeroes in DIGIT1..10. Using MPASM on a 16F690. Any ideas?" +
• I tryed to divide 36/360. But instead 0.1 i get 0.36. This happens with every combination where the REGA is lower then REGB.+
• spamrobson2TakeThisOuT at @spam@mts.net asks: " Looking for the rule that explains the order in which you multiply, add, subtract and divide. Example 811/5+900x4-60" James Newton replies: In general, multiply and divide first, then add and subtract. There is an expression evaluator that may help at http://www.sxlist.com/techref/expeval2.asp. For more, search for "operator precedence".

+

 file: /Techref/microchip/math/32bmath-ph.htm, 39KB, , updated: 2017/2/17 17:04, local time: 2022/1/20 23:21, owner: JMN-EFP-786, TOP NEW HELP FIND:  3.84.132.40:LOG IN

 ©2022 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions?Please DO link to this page! Digg it! / MAKE! 32-bit signed integer math routines. add, subtract, multiply, divide, round, sqrt, bin2dec, dec2bin. By Peter Hemsley.

After you find an appropriate page, you are invited to your to this massmind site! (posts will be visible only to you before review) Just type a nice message (short messages are blocked as spam) in the box and press the Post button. (HTML welcomed, but not the <A tag: Instead, use the link box to link to another page. A tutorial is available Members can login to post directly, become page editors, and be credited for their posts.

Attn spammers: All posts are reviewed before being made visible to anyone other than the poster.
 Did you find what you needed? "No. I'm looking for: " "No. Take me to the search page." "No. Take me to the top so I can drill down by catagory" "No. I'm willing to pay for help, please refer me to a qualified consultant" "No. But I'm interested. me at when this page is expanded."

Welcome to sxlist.com!

Site supported by
& kind contributors
just like you!

(here's why

Copies of the site on CD
are available at minimal cost.

.