divide by 10 and divide by 6 using bit shifts+addition
Moderator: Moderators
divide by 10 and divide by 6 using bit shifts+addition
Does anyone happen to have a general algorithm for dividing by 10 and by 6 using shifts/addition? debating on whether to go this direction, or to code it into a table...
-Thom
-Thom
- NovaSquirrel
- Posts: 423
- Joined: Fri Feb 27, 2009 2:35 pm
- Location: Fort Wayne, Indiana
- Contact:
Re: divide by 10 and divide by 6 using bit shifts+addition
The big Unsigned Integer Division Routines thread has routines for division by 6 and 10.
Re: divide by 10 and divide by 6 using bit shifts+addition
8-bit dividing by 10 is the same as doing 16-bit multiplication by 0x1A (00011010), then discarding the low byte. So that's x << 4 + x << 3 + x << 1 in 16-bit math.
Dividing by 6 is multiply by 0x2B (00101011), or x << 5 + x << 3 + x << 1 + x.
16-bit shifts and adds take up code and time.
Then there's the really stupid way to divide, subtracting in a loop, if you don't care about speed, it's a decent way.
But lookup tables are really cheap, just 256 bytes of ROM for 8-bit math.
Dividing by 6 is multiply by 0x2B (00101011), or x << 5 + x << 3 + x << 1 + x.
16-bit shifts and adds take up code and time.
Then there's the really stupid way to divide, subtracting in a loop, if you don't care about speed, it's a decent way.
But lookup tables are really cheap, just 256 bytes of ROM for 8-bit math.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
- rainwarrior
- Posts: 8062
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: divide by 10 and divide by 6 using bit shifts+addition
To clarify, this is a fixed point approximation technique. The results are not entirely accurate.Dwedit wrote:8-bit dividing by 10 is the same as doing 16-bit multiplication by 0x1A (00011010), then discarding the low byte. So that's x << 4 + x << 3 + x << 1 in 16-bit math.
Dividing by 6 is multiply by 0x2B (00101011), or x << 5 + x << 3 + x << 1 + x.
16-bit shifts and adds take up code and time.
The approximation works because a division by 256 is "cheap", so you can rescale the input with a pre-multiply.
Code: Select all
x / d = x * a / 256
d = a / 256
a = 256 / d
d = 10 --> a = 256 / 10 = 25.6
x / 10 = x * 25.6 / 256
d = 6 --> a = 256 / 6 = 42.666...Code: Select all
⌊ 69 / 10 ⌋ = 6 (6.9)
⌊ 69 * 26 / 256 ⌋ = 7 (7.0078125)Dwedit, I'm curious why you offered these numbers in hexadecimal and binary but not decimal. What significance do they have in hex/bin?
Re: divide by 10 and divide by 6 using bit shifts+addition
I'm arbitrarily going to guess that the OP is either converting frames or seconds to the next larger unit ... perhaps, rather than implementing division, it makes sense to store the time in BCsexagesimal ?
Re: divide by 10 and divide by 6 using bit shifts+addition
(this is for Wizard of Wor)
Nah, I just need to be able to calculate from a sprite position the nearest dungeon box that he's in (the dungeon is implemented as a 10x6 array of squares), so that I can implement collision detection and the like.
-Thom
Nah, I just need to be able to calculate from a sprite position the nearest dungeon box that he's in (the dungeon is implemented as a 10x6 array of squares), so that I can implement collision detection and the like.
-Thom
Re: divide by 10 and divide by 6 using bit shifts+addition
So it's division by 24 (which may involve division by 3 or 6 as an intermediate step) to convert from sprite coordinates to metatile coordinates, then multiply by 10 or by 6 (depending on whether row-major or column-major) to convert metatile coordinates to an address in the backing map. I don't see where division by 10 enters into it, except during conversion of a score to decimal.
Re: divide by 10 and divide by 6 using bit shifts+addition
Oh ok, I was thinking to derive the X and Y values seperately, but.. ok..tepples wrote:So it's division by 24 (which may involve division by 3 or 6 as an intermediate step) to convert from sprite coordinates to metatile coordinates, then multiply by 10 or by 6 (depending on whether row-major or column-major) to convert metatile coordinates to an address in the backing map. I don't see where division by 10 enters into it, except during conversion of a score to decimal.
-Thom
Re: divide by 10 and divide by 6 using bit shifts+addition
In binary, you can see the sequence of shifts and adds to do the multiply. Multiplying by 00110011 means x << 0 + x << 1 + x << 4 + x << 5 because those bits are set in the binary number.rainwarrior wrote:Dwedit, I'm curious why you offered these numbers in hexadecimal and binary but not decimal. What significance do they have in hex/bin?
And hex because I'm used to expressing reciprocal approximations in hex. On 32-bit arm, I'd always do 0x100000000 / x, then add 1, and use UMULL to do division. Here I did 0x100 / x + 1, but I might have needed some more precision here.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
- rainwarrior
- Posts: 8062
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: divide by 10 and divide by 6 using bit shifts+addition
Ah, yes that makes sense.Dwedit wrote:In binary, you can see the sequence of shifts and adds to do the multiply.
Re: divide by 10 and divide by 6 using bit shifts+addition
Wound up using omegamatrix's div by 24 routine:
As it turns out, I was being derp by not realizing that I needed to count pixels, not boxes for the divisor, thanks tepples. 
-Thom
Code: Select all
;Divide by 24
;15 bytes, 27 cycles
_div24: lsr
lsr
lsr
sta temp
lsr
lsr
adc temp
ror
lsr
adc temp
ror
lsr
rts
-Thom
Re: divide by 10 and divide by 6 using bit shifts+addition
Is there a complimentary routine for returning the modulus? I'm needing to do fine adjustment of the division to indicate whether I am actually as far into a box as I can be physically.
-Thom
-Thom