Consider the following as a reference implementation:
/* calculates (a * b) / c */
uint32_t muldiv(uint32_t a, uint32_t b, uint32_t c)
{
uint64_t x = a;
I suppose there are reasons you can't do
x = a/c;
x = x*b;
are there? And maybe add
y = b/c;
y = y*a;
if ( x != y )
return ERROR_VALUE;
Note that, since you're using integer division, a*b/c
and a/c*b
might lead to different values if c
is bigger than a
or b
. Also, if both a
and b
are smaller than c
it won't work.
The simplest way would be converting the intermediar result to 64 bits, but, depending on value of c, you could use another approach:
((a/c)*b + (a%c)*(b/c) + ((a%c)*(b%c))/c
The only problem is that the last term could still overflow for large values of c
. still thinking about it..
If b and c are both constants, you can calculate the result very simply using Egyptian fractions.
For example. y = a * 4 / 99 can be written as
y = a / 25 + a / 2475
You can express any fraction as a sum of Egyptian fractions, as explained in answers to Egyptian Fractions in C.
Having b and c fixed in advance might seem like a bit of a restriction, but this method is a lot simpler than the general case answered by others.
If b = 3000000000 => qn = 3000000000, qn*2 will be overflowed. So I edit the code of Sven Marnach.
uint32_t muldiv(uint32_t a, uint32_t b, uint32_t c)
{
uint32_t q = 0; // the quotient
uint32_t r = 0; // the remainder
uint32_t qn = b / c;
uint32_t rn = b % c;
while (a)
{
if (a & 1)
{
q += qn;
if (qn >= UINT32_MAX) {
cout << "CO CO" << endl;
}
r += rn;
if (r >= c)
{
q++;
r -= c;
}
}
a >>= 1;
qn <<= 1;
int temp = rn;
if (rn > INT32_MAX) {
// rn times 2: overflow
rn = UINT32_MAX;// rn
temp = (temp - INT32_MAX) * 2; // find the compensator mean: rn * 2 = UINT32_MAX + temp
qn++;
rn = rn - c + temp;
}
else {
rn <<= 1;
if (rn >= c)
{
qn++;
rn -= c;
}
}
}
//return r;
return q;
}
Searching on www.google.com/codesearch turns up a number of implementations, including this wonderfuly obvious one. I particularly like the extensive comments and well chosen variable names
INT32 muldiv(INT32 a, INT32 b, INT32 c)
{ INT32 q=0, r=0, qn, rn;
int qneg=0, rneg=0;
if (c==0) c=1;
if (a<0) { qneg=!qneg; rneg=!rneg; a = -a; }
if (b<0) { qneg=!qneg; rneg=!rneg; b = -b; }
if (c<0) { qneg=!qneg; c = -c; }
qn = b / c;
rn = b % c;
while(a)
{ if (a&1) { q += qn;
r += rn;
if(r>=c) { q++; r -= c; }
}
a >>= 1;
qn <<= 1;
rn <<= 1;
if (rn>=c) {qn++; rn -= c; }
}
result2 = rneg ? -r : r;
return qneg ? -q : q;
}
http://www.google.com/codesearch/p?hl=en#HTrPUplLEaU/users/mr/MCPL/mcpl.tgz|gIE-sNMlwIs/MCPL/mintcode/sysc/mintsys.c&q=muldiv%20lang:c
I have adapted the algorithm posted by Paul for unsigned ints (by omitting the parts that are dealing with signs). The algorithm is basically Ancient Egyptian multiplication of a
with the fraction floor(b/c) + (b%c)/c
(with the slash denoting real division here).
uint32_t muldiv(uint32_t a, uint32_t b, uint32_t c)
{
uint32_t q = 0; // the quotient
uint32_t r = 0; // the remainder
uint32_t qn = b / c;
uint32_t rn = b % c;
while(a)
{
if (a & 1)
{
q += qn;
r += rn;
if (r >= c)
{
q++;
r -= c;
}
}
a >>= 1;
qn <<= 1;
rn <<= 1;
if (rn >= c)
{
qn++;
rn -= c;
}
}
return q;
}
This algorithm will yield the exact answer as long as it fits in 32 bits. You can optionally also return the remainder r
.