piclist 2001\04\06\102145a >
Thread: Rounding to closest 10's multiple, code enclosed :)
www.piclist.com/techref/microchip/devices.htm?key=pic
flavicon
face BY : Kübek Tonyemail (remove spam text)



Hi,
as I promised I've hammered out some rounding code and
will attach the rounding to closest 10s multiple below.
The rounding to closest 1's multiple will follow
in 5'min as an separate posting.

Some minor comments:
It's coded for 24 bit input/output trough fsr0,
uses some 18Cxx specific instructions ( wouldn't be
to hard to convert to other pic's ).
It's not fully omptimized, I'll leave that as an exerzice
to the user ( there are some places that can be improved )
The rounding takes about 190'ish instructions worst case.
As far as I can tell there really are no faster options
to round an 24 bit value. But please prove me wrong :)

And without the input from Bob,Roman and Scott it sure would
have been a rougher ride. Thanks.

Use at will.

; ***********************************************************************
; ROUND_TENS_FSR0_24bit - Rounds 24 bit unsigned value value pointed to by
fsr0
; according to (tens)granularity in w
; FSR0 must point to MSB of input, output will overwrite input at exit
; Granularity can be 0x05, 0x02, 0x01
; 0x05 round to nearest decimal '50', 0x02 round to nearest decimal '20'
etc.
; In other words low nibble of w decides the granularity for the tens digit
( as 'bcd' )
; Other granularities are untested and may/may not nork.
;
; Executes in about 190 cycles worst case
; About 180 instructions are used. I.e mostly unrolled code
;
; Algorithm:
; * Adds half granularity to input. ( i.e. for granularity 0x05 ( 50 ) 25 is
added )
; * 'Exctract' each bit's addition to the ones and tens digit
;   separately. After the actual 'extraction' they are normalized ( to 0-9
range ).
; * If tens digit is larger then granularity, granulairty is subtracted from
it
;   until next subtraction generates negative result.
; * Multiply tens digit by 10 ( i.e. to 'real' value )
; * Add the ones
; * Subtract the result from the input and overwrite with output.
;
;                      
; Ram usage ( all in access bank ):
; ARG2_24       1 byte 'tens'
; ARG2_24+1     1 byte 'ones'
; Temp          1 byte 'granularity'/10 ( i.e. input in w )
; Temp+1        1 byte for calculation of 'real' granularity/2  
;
ROUND_TENS_FSR0_24bit
       GLOBAL  ROUND_TENS_FSR0_24bit
       ; save granularity
       MOVWF   Temp,A
       ; set pointer to lsb of input
       MOVF    POSTINC0,W,A
       MOVF    PREINC0,W,A     ; pointer now to lsb and lsb in w
       ; add half of granularity(real) to input
       ;, make a copy of granularity
       MOVFF   Temp,Temp+1
       ; calculate 'real' granularity/2 ( i.e. input granularity*5 )
       ; multiply by 4
       BCF     STATUS,C        ; clear carry
       RLCF    Temp+1,F,A      ; multiply with 2
       RLCF    Temp+1,F,A      ; multiply with 4
       ; add 'pseudo' granularity ( input )
       MOVF    Temp,W,A
       ADDWF   Temp+1,W,A      ; and add them, w = input granularity*5 ( or
rather 'real' granularity/2 )
       ; add to input
       ADDWF   POSTDEC0,F,A    ; add to lsb and set pointer to middle byte
       MOVF    INDF0,W,A       ; get middle byte
       BTFSC   STATUS,C
       ADDLW   D'1'            ; propagate the carry
       MOVWF   POSTDEC0,A      ; save it and set pointer to msb
       BTFSC   STATUS,C
       INCF    INDF0,F,A       ; propagate the carry and leave pointer to
msb
       
       ; clear ones and tens bytes
       CLRF    ARG2_24+1,A     ; temp storage for the ones
       CLRF    ARG2_24,A       ; temp storage for the tens
       
       ; * calcualte top byte byte low nibble
       MOVF    INDF0,W,A       ;
       ANDLW   b'00001111'     ; mask out lowest nibble
       ; if zero skip to next nibble
       BTFSC   STATUS,Z
       GOTO    ROUND_TENS_FSR0_NIB2
       
       BTFSC   INDF0,0,A       ; lowest bit set in low nibble ?
       ADDLW   D'5'            ; yes add  5, it's worth '6' not 1
       MOVWF   ARG2_24+1,A     ; start value for the ones

       ; calculate tens byte, bit 'tens-values' from bit 0 : 3,7,4,8
       MOVLW   0x00
       BTFSC   INDF0,0,A       ; test bit
       ADDLW   D'3'            ; add it's 'tens' value to w
       BTFSC   INDF0,1,A       ; test bit
       ADDLW   D'7'            ; add it's 'tens' value to w
       BTFSC   INDF0,2,A       ; test bit
       ADDLW   D'4'            ; add it's 'tens' value to w
       BTFSC   INDF0,3,A       ; test bit
       ADDLW   D'8'            ; add it's 'tens' value to w
       ; and move the result to the tens byte
       MOVWF   ARG2_24,A       ; tens byte

ROUND_TENS_FSR0_NIB2

       ; calcualte top byte high nibble
       SWAPF   INDF0,W,A       ;
       ANDLW   b'00001111'     ; mask out lowest nibble

       BTFSC   INDF0,4,A       ; lowest bit set in high nibble ?
       ADDLW   D'5'            ; yes add  5, it's worth '6' not 1
       ADDWF   ARG2_24+1,F,A   ; add it to ones
       ; calculate tens byte, bit 'tens-values' from bit 0 : 7,5,0,0 ( i.e.
skip test of top two bits )
       MOVLW   0x00
       BTFSC   INDF0,4,A       ; test bit
       ADDLW   D'7'            ; add it's 'tens' value to w
       BTFSC   POSTINC0,5,A    ; test bit ***AND** increment pointer to
middle byte of input
       ADDLW   D'5'            ; add it's 'tens' value to w
       ; and add result to the tens byte
       ADDWF   ARG2_24,F,A     ; add to tens byte


       ; * calcualte middle byte low nibble
       MOVF    INDF0,W,A       ;
       ANDLW   b'00001111'     ; mask out lowest nibble
       ; if zero skip to next nibble
       BTFSC   STATUS,Z
       GOTO    ROUND_TENS_FSR0_NIB3

       BTFSC   INDF0,0,A       ; lowest bit set in low nibble ?
       ADDLW   D'5'            ; yes add  5, it's worth '6' not 1
       ADDWF   ARG2_24+1,F,A   ; add it to ones
       ; calculate tens byte, bit 'tens-values' from bit 0 : 5,1,2,4
       MOVLW   0x00
       BTFSC   INDF0,0,A       ; test bit
       ADDLW   D'5'            ; add it's 'tens' value to w
       BTFSC   INDF0,1,A       ; test bit
       ADDLW   D'1'            ; add it's 'tens' value to w
       BTFSC   INDF0,2,A       ; test bit
       ADDLW   D'2'            ; add it's 'tens' value to w
       BTFSC   INDF0,3,A       ; test bit
       ADDLW   D'4'            ; add it's 'tens' value to w
       ; and add result to the tens byte
       ADDWF   ARG2_24,F,A     ; add to tens byte

ROUND_TENS_FSR0_NIB3

       ; calcualte middle byte high nibble
       SWAPF   INDF0,W,A       ;
       ANDLW   b'00001111'     ; mask out lowest nibble
       BTFSC   INDF0,4,A       ; lowest bit set in high nibble ?
       ADDLW   D'5'            ; yes add  5, it's worth '6' not 1
       ADDWF   ARG2_24+1,F,A   ; add it to ones
       ; calculate tens byte, bit 'tens-values' from bit 0 : 9,9,8,6
       MOVLW   0x00
       BTFSC   INDF0,4,A       ; test bit
       ADDLW   D'5'            ; add it's 'tens' value to w
       BTFSC   INDF0,5,A       ; test bit
       ADDLW   D'1'            ; add it's 'tens' value to w
       BTFSC   INDF0,6,A       ; test bit
       ADDLW   D'2'            ; add it's 'tens' value to w
       BTFSC   POSTINC0,7,A    ; test bit *AND* increment pointer to lowest
byte of input
       ADDLW   D'4'            ; add it's 'tens' value to w
       ; and add result to the tens byte
       ADDWF   ARG2_24,F,A     ; add to tens byte


       ; * calculate lowest nibble of lowet byte
       ; note has no effect on the tens byte
       MOVF    INDF0,W,A       ;
       ANDLW   b'00001111'     ; mask out lowest nibble
       ADDWF   ARG2_24+1,F,A   ; add it to ones
       ; calculate top nibble 'ones' byte
       SWAPF   INDF0,W,A       ;
       ANDLW   b'00001111'     ; mask out lowest (prev. highest) nibble
       ; if zero skip and continue with normalization
       BTFSC   STATUS,Z
       GOTO    ROUND_TENS_FSR0_NORM

       BTFSC   INDF0,4,A       ; lowest bit set in top nibble ?
       ADDLW   D'5'            ; yes add  5, it's worth '6' not 1
       ADDWF   ARG2_24+1,F,A   ; add it to ones
       ; calculate tens byte, bit 'tens-values' from bit 4 : 1,3,6,2
       MOVLW   0x00
       BTFSC   INDF0,4,A       ; test bit
       ADDLW   D'1'            ; add it's 'tens' value to w
       BTFSC   INDF0,5,A       ; test bit
       ADDLW   D'3'            ; add it's 'tens' value to w
       BTFSC   INDF0,6,A       ; test bit
       ADDLW   D'6'            ; add it's 'tens' value to w
       BTFSC   INDF0,7,A       ; test bit, leave pointer to lsb of input
       ADDLW   D'2'            ; add it's 'tens' value to w
       ; and add it to the tens byte
       ADDWF   ARG2_24,F,A     ; save tens byte

       ; pointer fsr0 points to lsb of input here
ROUND_TENS_FSR0_NORM
       
       ; *** ones and tens updated now we need to add the overflow from the
ones
       ; to the tens ( i.e. ones and tens are NOT limited to 0-9 yet )
       ; Maximum value for the ones: 109
       ; Maximum value for the tens: 90  ( i.e. 90*10 = 900 )
       
       ; ** Normalize tens and ones digits **
       ; we start by subtracting 30 from the ones until negative, then add
ten until positive again
       ; after which we now it's in 0-9 range
       ; subtract 30 from ones        
       MOVLW   D'30'
ROUND_TENS_FSR0_SUB30
       ; add '3' to tens
       INCF    ARG2_24,F,A     ; +10
       INCF    ARG2_24,F,A     ; +20
       INCF    ARG2_24,F,A     ; +30
       ; subtract 30 from ones
       SUBWF   ARG2_24+1,F,A
       SKPNC   ; overflow, i.e. negative then add 10 until positive again
       GOTO    ROUND_TENS_FSR0_SUB30
       ; add 10 until positive again
       MOVLW   D'10'
ROUND_TENS_FSR0_ADD10
       ; remove ten from tens  
       DECF    ARG2_24,F,A     ; -10
       ; add 10 to ones
       ADDWF   ARG2_24+1,F,A  
       SKPC    ; positive ?
       GOTO    ROUND_TENS_FSR0_ADD10   ; nope still negative
       ; now ones are positive and below 10, i.e. we have successfully
subtracted
       ; the ones digit for the 24 bit input
       ; now we 'adjust' the tens digit to be inthe same range 0-9
       MOVLW   D'30'   ;i.e. 300
ROUND_TENS_FSR0_SUB300
       ; subtract 30 (300) from tens
       SUBWF   ARG2_24,F,A
       SKPNC   ; overflow, i.e. negative then add 10 until positive again
       GOTO    ROUND_TENS_FSR0_SUB300
       ; add 10(100) until positive again
       MOVLW   D'10'
ROUND_TENS_FSR0_ADD100
       ; add 10(100) to tens until postive
       ADDWF   ARG2_24,F,A
       SKPC    ; positive ?
       GOTO    ROUND_TENS_FSR0_ADD100  ; nope still negative
       ; now tens are also positive and below 10, i.e. we have successfully
subtracted
       ; the tens digit for the 24 bit input
       
       ; ** calculate granularity diff in the tens digit
       ; subtract granularity from the tens byte
       MOVF    ARG2_24,W,A     ; start value
ROUND_TENS_FSR0_GRAN_CHK
       MOVWF   ARG2_24,A       ; save start value ( or concecutive values )
       MOVF    Temp,W,A        ; get granularity
       ; subtract it from the tens
       SUBWF   ARG2_24,W,A
       ; check if negative or positive
       ; if positive/zero save result and try again
       BTFSS   STATUS,N
       GOTO    ROUND_TENS_FSR0_GRAN_CHK
       ; now we need to add the tens and ones, first 'multiply' the tens
       ; by 10
       BCF     STATUS,C
       RLCF    ARG2_24,F,A     ;tens = tens *2
       MOVFF   ARG2_24,Temp    ; overwrite the granularity ( we don't need
it anymore ) = tens *2
       RLCF    ARG2_24,F,A     ; tens*2 = tens*2*2
       RLCF    ARG2_24,W,A     ; tens*2*2 = tens*2*2*2 = tens*8
       ; add temp(tens*2) and tens*8 to w
       ADDWF   Temp,W,A        ; w = tens*10
       ; then we it with the ones
       ADDWF   ARG2_24+1,W,A
       ; w = tens*10 + ones
       ; now we subtract this from the input
       SUBWF   POSTDEC0,F,A    ; subtract and set pointer to middle byte
       SKPC    
       DECF    INDF0,F,A       ; propagate the borrow
       MOVF    POSTDEC0,W      ; set pointer to msb
       SKPC    
       DECF    INDF0,F,A       ; propagate the borrow and leave pointer to
msb of input
                                       
       RETURN






















Tony Kübek, Flintab AB            
²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²
E-mail: .....tony.kubekEraseMEspamTakeThisOuTflintab.com
²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²

--
http://www.piclist.com hint: To leave the PICList
@spam@piclist-unsubscribe-requestEraseMEspammitvma.mit.edu


<200104061411.QAA21049@mn10.swip.net> quoted-printable

See also: www.piclist.com/techref/microchip/devices.htm?key=pic
Reply You must be a member of the piclist mailing list (not only a www.piclist.com member) to post to the piclist. This form requires JavaScript and a browser/email client that can handle form mailto: posts.
Subject (change) Rounding to closest 10's multiple, code enclosed :)

month overview.

new search...