PDA

View Full Version : DIV32 instead of floating point routines?



Tomasm
- 13th April 2004, 20:41
Hi everyone,

I have to calculate with 16bit numbers, but the result has to be 24 or 32 bit:

result = a * 5 / 3 ' 0 < a < 60000

The result sometimes doesnt fit in a word variable. Therefore I used the floating point routines, but that needs to much flash. Is there a way to do this calculation with div32?

Thanks in advance,

Best Regards,

Tomas

Darrel Taylor
- 16th April 2004, 12:10
I suppose it depends on the accuracy you need. But if you only want the integer of the result, here's one way to do it.


a var word ' 0-60000
result var word[2] ' 32-bit result, although largest is 17-bit with input of 0-60,000
ResHigh var result[1]
ResLow var result[0]
remainder var word
temp var word

a = 60000 ' a test number

ResLow = a / 3
remainder = a // 3 * 15 / 10
temp = ResLow - 13107
ResHigh = temp.15 ^ 1
ResLow = ResLow * 5
Reslow = Reslow + Remainder

LCDout $FE,1,Hex4 ResHigh,":",hex4 ResLow
I know it looks strange, but try it. It works. ;)

Best regards,
&nbsp;&nbsp;&nbsp;Darrel

Tomasm
- 17th April 2004, 21:12
Hi Darrel,

yes, a integer result is sufficent for me.

I coded a solution with Div32 but your solution is much shorter.

Thank you very much, Darrel.

Best regards,

Tomas

Darrel Taylor
- 17th April 2004, 22:29
Hi again Tomas,

I wrote that example rather quick, just trying to beat Melanie to the punch.&nbsp; After looking at it again, I saw that it could be reduced even further. This way uses fewer variables, and is a bit shorter too.
a var word ' 0-60000
result var word[2] ' 32-bit result, although largest is 17-bit
ResHigh var result[1]
ResLow var result[0]

a = 60000 ' a test number

ResLow = a / 3
ResHigh = ((ResLow - 13107) >> 15) ^ 1
ResLow = ResLow * 5 + (a // 3 * 15 / 10)
Best regards,
&nbsp;&nbsp;&nbsp;Darrel

misk
- 19th April 2004, 10:58
Hi Darrel,
can You explain how to reach that result?
Thank You.
Misk

Darrel Taylor
- 22nd April 2004, 08:46
Oh geez, sorry misk, I missed this question.

Basically, it just uses the divide first to reduce the size of the numbers, then does the multiply. This helps keep it within the 65535 limit. (a / 3 * 5) is the same as (a * 5 / 3)

Since the largest result of (60,000 * 5 / 3) = 100,000 which is 0001:86A0, you really only have to worry about 1 bit above the 65535 limit. In this case it worked out nicely that the largest number you can multiply by 5 and still be within 65535 is 13107. Anything larger, and you just add an extra bit, then do the multiply like normal.

After dividing the original number:
ResLow = a / 3

If you subtract 13107 from it, and it becomes negative, then the twos compliment value of the negative number will have bit 15 as a 1. This means that the number is not large enough to cause an overflow. So, the next statement just isolates that bit15 and inverts it with an xor operator (^ 1). This now becomes the low bit of the high word.

ResHigh = ((ResLow - 13107) >> 15) ^ 1

It kind of like saying.. If (a / 3 * 5) > 65535 then ResHigh = 1.
If you could actually do that in PBP, it would be much easier.

Now that the High word is complete, you can just do the multiply times 5 and just let it overflow (if it does).

Finally, in the first divide by 3, there is usually something left over. It's always either a 0, 1, or 2 (a // 3) the modulas of 3.

To get the decimal of that modulas, you would normally divide that number by the original divisor. Therefore, 0/3 = 0, 1/3 = .3333, 2/3 = .6666. But in this case, it also needs to be multiplied by 5. 0*5=0, .333*5=1.6666, .6666*5=3.3333.
Then the resulting integer is added to the original result. In the above formula, I rounded it off to 1.5 or 15/10 since you get the same integer value. Now, 0*15/10=0, 1*15/10=1 and 2*15/10=3 in integer results.

ResLow = ResLow * 5 + (a // 3 * 15 / 10)

And Ummm, or Ohhh, duhh, oh Crap.

Now I can see that by not considering the remainder when getting the High bit, there is 1 number that the formula doesn't work for. 39321 the result ends up as 0001:FFFF instead of 0000:FFFF. Not good.

Thanks misk! That would have probably driven Tomasm crazy.

See next Post.

Darrel Taylor
- 22nd April 2004, 08:50
Tomasm,

Thanks to misk's question I found that there is one number out of 60,000 that that formula has a problem with.

39321 the result ends up as 0001:FFFF instead of 0000:FFFF.

here's a possible fix:
a var word ' 0-60000
result var word[2] ' 32-bit result, although largest is 17-bit
ResHigh var result[1]
ResLow var result[0]

a = 60000 ' a test number

ResLow = a / 3
if a <> 39321 then
ResHigh = ((ResLow - 13107) >> 15) ^ 1
else
ResHigh = 0
endif
ResLow = ResLow * 5 + (a // 3 * 15 / 10)Not pretty, but it's works better.

Best regards,
&nbsp;&nbsp;&nbsp;Darrel