division through a constant

Started by
13 comments, last by Boops 20 years, 2 months ago
That was by hand. Though the infinite series of powers of two that makes up 1/3 is very well behaved, so it was a lot easier to do than it looks.
Advertisement
Woot, thanks for pointing that out

I guess I''ll stick with x/48
What is the range of values for X? If they're not too large, you can use SiCrane's great code, just use the first few shifts and discard the rest. His algorithm begins:

(X >> 6) + (X >> 8) + (X >> 10) + (X >> 12)

If X is always less than 4096, X >> 12 will always be zero, as will all the terms to the right of it in the original algorithm. Therefore you can just use:

(X >> 6) + (X >> 8) + (X >> 10)

And get perfectly accurate results every time. And that may be faster than doing the division. Profile it.

EDIT: Nevermind, SiCrane is wrong. He forgot he's dealing with integer math. For example, take 48*7 = 336. Passed through his algorithm:

(336/64) + (336/256) + (336/1024) ...

Taken as integers, you get 5+1+0 = 6. Taken as floating-point numbers, you get 5.25 + 1.3125 + 0.328125 = 6.89, and doing the other divisions/additions will bring it to exactly 7.

~CGameProgrammer( );

Screenshots of your games or desktop captures -- Post screenshots of your projects. There's already 134 screenshot posts.

[edited by - CGameProgrammer on February 21, 2004 8:01:25 AM]
~CGameProgrammer( );Developer Image Exchange -- New Features: Upload screenshots of your games (size is unlimited) and upload the game itself (up to 10MB). Free. No registration needed.
No, I remembered that this was integer math. It''s just that it''s easier to explain the derivation of the broken formula than it is to explain the derivation of the actual correct bitshift division method. And the broken formula is sufficient to explain why it''s a bad idea.

If you want an actual correct division by 48 method using shifts, here it is (for 32 bit unsigned ints):

(((n - ((n - ((n - ((n - ((n - ((n - ((n - ((n - ((n - ((n - ((n - ((n - ((n - ((n - ((n - ((n - ((n - ((n - ((n - ((n - ((n - ((n - ((n - ((n - ((n - ((n - ((n - ((n - ((n - ((n - ((n - ((n - 0) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1)) >> 1) >> 4)
> I''m using pure integer math, can''t multiply by 1/48
Oh, but you can! Use fixed-point arithmetic. Derivation:
quote:Problem: calculate a/b. If we can''t shift or divide, we have to multiply a by (1/b). First thought: let r = c/b, then q = (r * a) / c (c > a,b). Unfortunately, q <= a/b, due to truncation during the divisions. We can avoid this by ''padding'' the numerator: r = ((c+b-1)/b). Finally, choose c = 0x100000000, and we can divide by c for free - the "mul r" instruction places the upper 32 bits of the product into edx, which is then equal to a/b.

(from a previous thread)
E8 17 00 42 CE DC D2 DC E4 EA C4 40 CA DA C2 D8 CC 40 CA D0 E8 40E0 CA CA 96 5B B0 16 50 D7 D4 02 B2 02 86 E2 CD 21 58 48 79 F2 C3

This topic is closed to new replies.

Advertisement