piclist 2001\04\06\103828a >
Thread: Rounding to closest 1's multiple, code enclosed :)
www.piclist.com/techref/microchip/devices.htm?key=pic
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 1s multiple below.
The rounding to closest 10's multiple is posted separately.

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 88 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_ONES_FSR0_24bit - Rounds 24 bit unsigned value value pointed to by
fsr0
; according to (ones)granularity in w
; FSR0 must point to MSB of input, output will overwrite input at exit
; Granularity can be 0x05, 0x02 ( others not tested )
; 0x05 round to nearest decimal '5', 0x02 round to nearest decimal '2' etc.
; In other words low nibble of w decides the granularity for the ones digit
; Other granularities are untested and may/may not nork.
;
; Executes in about 88 cycles worst case
; About 65 instructions are used. I.e mostly unrolled code
;
; Algorithm:
; * Adds half granularity to input. ( i.e. for granularity 0x05 ( 5 ) 2 is
; * 'Exctract' each bit's addition to the ones digit
;    After the actual 'extraction' it is normalized ( to 0-9 range ).
; * If ones digit is larger then granularity, granulairty is subtracted from
it
;   until next subtraction generates negative result.
; * Subtract the result from the input and overwrite with output.
;
;
; Ram usage ( all in access bank ):
; ARG2_24+1     1 byte 'ones'
; Temp          1 byte 'granularity' ( i.e. input in w )
;

ROUND_ONES_FSR0_24bit
GLOBAL  ROUND_ONES_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
BCF     STATUS,C
RRCF    Temp,W,A
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

; * calcualte top byte byte low nibble
MOVF    INDF0,W,A       ;
ANDLW   b'00001111'     ; mask out lowest nibble
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
; calcualte top byte high nibble
SWAPF   INDF0,W,A       ;
ANDLW   b'00001111'     ; mask out lowest nibble
BTFSC   POSTINC0,4,A    ; lowest bit set in high nibble ? *set
pointer to middle byte *
ADDLW   D'5'            ; yes add  5, it's worth '6' not 1
ADDWF   ARG2_24+1,F,A   ; add it to ones
; * calcualte middle byte low nibble
MOVF    INDF0,W,A       ;
ANDLW   b'00001111'     ; mask out lowest nibble
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
; calcualte middle byte high nibble
SWAPF   INDF0,W,A       ;
ANDLW   b'00001111'     ; mask out lowest nibble
BTFSC   POSTINC0,4,A    ; lowest bit set in high nibble ?*set
pointer to lowest byte *
ADDLW   D'5'            ; yes add  5, it's worth '6' not 1
ADDWF   ARG2_24+1,F,A   ; add it to ones
; * calculate lowest nibble of lowest 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
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

; pointer fsr0 points to lsb of input here
ROUND_ONES_FSR0_NORM
; *** ones updated now we need to normalize it ( i.e. remove
everything above 10 )
; Maximum value for the ones: 109
; we start by subtracting 30 from the ones until negative, then add
ten until positive again
; after which we know it's in 0-9 range
; subtract 30 from ones
MOVLW   D'30'
ROUND_ONES_FSR0_SUB30
; subtract 30 from ones
SUBWF   ARG2_24+1,F,A
SKPNC   ; overflow, i.e. negative then add 10 until positive again
GOTO    ROUND_ONES_FSR0_SUB30
; add 10 until positive again
MOVLW   D'10'
; add 10 to ones
SKPC    ; positive ?
GOTO    ROUND_ONES_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

; ** calculate granularity diff in the ones digit
; subtract granularity from the ones byte
MOVF    ARG2_24+1,W,A   ; start value
ROUND_ONES_FSR0_GRAN_CHK
MOVWF   ARG2_24+1,A     ; save start value ( or concecutive values )
MOVF    Temp,W,A        ; get granularity
; subtract it from the tens
SUBWF   ARG2_24+1,W,A
; check if negative or positive
; if positive/zero save result and try again
BTFSS   STATUS,N
GOTO    ROUND_ONES_FSR0_GRAN_CHK
; get the diff into w
MOVF    ARG2_24+1,W,A   ; granularity diff
; 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.kubekflintab.com
²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²

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

<200104061432.QAA25481@mn10.swip.net> quoted-printable