Searching \ for 'Decimal to Percentage Routine' in subject line. () Help us get a faster server
FAQ page: www.piclist.com/techref/index.htm?key=decimal+percentage
Search entire site for: 'Decimal to Percentage Routine'.

Truncated match.
'Decimal to Percentage Routine'
1998\12\07@233815 by  Greetings all !

I am trying to come up with a routine to convert a byte value to a
percentage.  That is, for an input value of zero, the output would be
zero.  For an input of 255, the output would be 100.  The obvious
solution is:  Percentage = Trunc(Decimal / 2.55).  Since I don't know of
an easy way to divide by a fractional number, I came up with this
alternative:
Percentage = (Decimal * 100) / 255.  Now I am faced with having to use
sixteen bit operations for a problem that has eight bit values for both
input and output.  If there is an easier way to do this, would someone
please enlighten me?  I have been thinking this over for quite some time,
so maybe I "can't see the forest for the trees."

Kelly Kohls
Home E-Mail Address: kkohls juno.com or n5tle qsl.net
Homepage URL: http://www.qsl.net/n5tle

___________________________________________________________________
Get completely free e-mail from Juno at http://www.juno.com/getjuno.html
or call Juno at (800) 654-JUNO [654-5866]  Kelly J Kohls wrote:
> Percentage = (Decimal * 100) / 255.  Now I am faced with having to use
> sixteen bit operations for a problem that has eight bit values for both
> input and output.

If you need speed and are not too worried about using up code space,
you could use a lookup table since  you have only(!) 256 possible values.

I *think* this is how it goes:

movlw   LOW  percent    ; get low byte of percent table address
addwf   input,F         ; and add it to input value to get offset
movlw   HIGH percent    ; get high byte of percent table adress
skpnc                   ; would index cross a page boundary?
addlw   0x01            ; yes. Increment page number
movf    input,W         ; get the offset into the table
call    percent         ; and look up the corresponding value
movwf   output          ; .. or whatever you wanna do with it.

....

percent movwf   PCL
retlw   0x00            ; 0/255 = 0%
retlw   0x00            ; 1/255 = 0%
retlw   0x01            ; 2/255 = 1%
retlw   0x01            ; 3/255 = 1%
retlw   0x02            ; 4/255 = 2%
.
.
.
retlw   0x64            ; 255/255 = 100%

-------------------------------------------------------------------------------
Mike, N6KUY xyzzy acm.org
Linux religious dogma: The Gates of Hell shall not prevail
GCS/M { -d+ p+ c++ l u++ e+(*) m++(-) s/+ !n-(---) h-- !f g+ w+ t++ r-(--) y+ }
-------------------------------------------------------------------------------  Hi,

here is a pretty simple solution:

Percentage = (Decimal * 101) >> 8

The operation SHIFT RIGHT 8 should not be commenced. Simply take the MSB
of the result, and it is!

Imre

On Mon, 7 Dec 1998, Kelly J Kohls wrote:

{Quote hidden}  > Van: Kelly J Kohls <kkohls JUNO.COM>
> Aan: PICLIST MITVMA.MIT.EDU
> Onderwerp: Decimal to Percentage Routine
> Datum: dinsdag 8 december 1998 5:35
>
> Greetings all !

Greetings to you, Kelly.

{Quote hidden}

The 'solution' ?  Just don't divide with 'nasty' numbers.  Create a number
that is 256 times too big, and than throw way the low-byte ...  In other
words Multiply the number with 100 and that divide by 256 (throw away the
Low-byte).  That should work.

(255 *100)/256 = 99%

Greetz,
Rudy Wieser  On Mon, 7 Dec 1998 22:20:02 -0800, you wrote:

>Kelly J Kohls wrote:
>> Percentage = (Decimal * 100) / 255.  Now I am faced with having to use
>> sixteen bit operations for a problem that has eight bit values for both
>> input and output.
>
>If you need speed and are not too worried about using up code space,
>you could use a lookup table since  you have only(!) 256 possible values.
And remember that as 1% is more than two counts, you only need to
lookup the top 7 bits, requiring at most 128 entries in the table.
Fewer if accuracy isn't critical - 64 entries would still be within
2%.   On Mon, 7 Dec 1998, Kelly J Kohls wrote:

>
> I am trying to come up with a routine to convert a byte value to a
> percentage.  That is, for an input value of zero, the output would be
> zero.  For an input of 255, the output would be 100.  The obvious
> solution is:  Percentage = Trunc(Decimal / 2.55).  Since I don't know of
> an easy way to divide by a fractional number, I came up with this
> alternative:
> Percentage = (Decimal * 100) / 255.  Now I am faced with having to use
> sixteen bit operations for a problem that has eight bit values for both
> input and output.  If there is an easier way to do this, would someone
> please enlighten me?  I have been thinking this over for quite some time,
> so maybe I "can't see the forest for the trees."

Try this. It's close, but not exactly what you ask (I divide by 256
instead of 255 - but there is an approximation available to fix this [I
don't have time to type it in now]):

;*******************************************************************
;scale_hex2dec
;  The purpose of this routine is to scale a hexadecimal byte to a
;decimal byte. In other words, if 'h' is a hexadecimal byte then
;the scaled decimal equivalent 'd' is:
;    d = h * 100/256.
;Note that this can be simplified:
;    d = h * 25 / 64 = h * 0x19 / 0x40
;Multiplication and division can be expressed in terms of shift lefts
;and shift rights:
;    d = [ (h<<4) + (h<<3) + h ] >> 6
;The program divides the shifting as follows so that carries are
automatically
;taken care of:
;    d =   (h + (h + (h>>3)) >> 1) >> 2
;
;Inputs:   W - should contain 'h', the hexadecimal value to be scaled
;Outputs:  W - The scaled hexadecimal value is returned in W
;Memory:   temp
;Calls:    none

scale_hex2dec
MOVWF   temp            ;Hex value is in W.
CLRC                    ;Clear the Carry bit so it doesn't affect
;the RRF
RRF     temp,F
CLRC
RRF     temp,F

RRF     temp,F          ;temp = h>>3
ADDWF   temp,F          ;temp = h + (h>>3)
RRF     temp,F          ;temp = (h + (h>>3)) >> 1
ADDWF   temp,F          ;temp = h + ((h + (h>>3)) >> 1)
RRF     temp,F
CLRC
RRF     temp,W          ;d = W = (h + (h + (h>>3)) >> 1) >> 2
RETURN   On Tue, 8 Dec 1998, Scott Dattalo wrote:

{Quote hidden}

You can make this approximation to improve things a little bit. First,
you want to perform this function:

p = d * 100 / 255

and the routine that I provide does this instead:

p = d * 100 / 256

So to modify my routine, you'll need to do something like this:

p' = p * 256 /255 ...............(1)

And you're still stuck with that nasty division. However, there's another
division trick you can try. Consider this power series expansion of
division:

N        N    /     / e \   / e \2  / e \3      \
-------  = --- * | 1 - |---| + |---| - |---| + ... |
v + e      v    \     \ v /   \ v /   \ v /       /

In your case, N, the dividend, is a constant (that is, the result
produced from my routine above multiplied by 256). The divisor has
been written as a sum of two variables. Now the object is to find a v that
is easy to divide (for example any power of 2). Since you're dividing by
255, you might as well choose v = 256 and e = 1. The equation then becomes
this:

N        N    /     / 1 \   / 1 \2  / 1 \3      \
-------  = --- * | 1 + |---| + |---| + |---| + ... |
v + e     256   \     \256/   \256/   \256/       /

When you substitute equation (1) back in and drop the high order terms you
get this:
/  1        1    \
p' = p * 256 * | ---  + ------- |
\ 256    256*256 /

/      1  \
= p * | 1 + --- |
\     256 /

Two observations:

1) This will not work with my routine because it does not save the
remainders while doing the computation. Thus the division by 256 is like a
shift right 8 positions, and there's nothing but zero to add to this. So
no rounding will occur. (I didn't realize this until type all of this
junk...) A corollary observation is that 256 is close enough to 255 so
that it really doesn't matter (is this true? , if not, perhaps
precompensating p by 1 would be sufficient to make it so.)

2) You can still use this work to form this approximation:

100 * d        25   /     / 1 \   / 1 \2  / 1 \3      \
-------  = d * -- * | 1 + |---| + |---| + |---| + ... |
255          64   \     \256/   \256/   \256/       /

All of the divisions are simple, so the evaluation should be fast.  Um, you mean e = -1 there, Scott, I suspect (Just a typo, you know
what you're doing, the equations are all right - just a dropped - sign
that you didn't catch on reviewing, I mention it in case you confused
anyone else <G>)

Mark, mwillis nwlink.com

Scott Dattalo wrote:
{Quote hidden}

^^^^  {s/b -1 here}  Greetings All!

Many thanks to all who responded to my inquiry.  After evaluating all of
the options presented and obtaining some information from the Internet on
integer division, I managed to get a routine working that implements the
following equation:

Percent = (Decimal * 20) / 51.

The divide algorithm that I used I obtained from Ian Kaplans website
(http://www.bearcave.com/software/divide.htm).  This algorithm implements
a radix-2 division operation.  If the algorithm ends up being too slow, I
still might use a table.  The resulting test program for this algorithm
ended up being about 140 lines long.  I considered sending it along with
this post, but thought it was too lengthy.  If anybody is interested in
the routine, let me know via a personal email.

Kelly Kohls
Home E-Mail Address: kkohls juno.com or n5tle qsl.net