tags:

views:

145

answers:

7

Given:

unsigned int a, b, c, d;

I want:

d = a * b / c;

and (a *b ) may overflow; also (b/c) may equal zero and give less accuracy.

Maybe a cast to 64-bits would get things to work, but I want to know the best way to get the most accurate result in d.

Is there any good solution?

+5  A: 

I would either:

  • Cast to 64 bits, if that will work for your ranges of a, b, and c.
  • Use an infinite precision library like GMP
  • Cast to a float or double and back, if you find those results acceptable.
Matt J
+1 for suggesting GMP
lothar
I think GMP is slightly overkill in this case. Two 32-bit ints divided by a 32-bit int will never exceed 64 bits any step, no matter which order you choose for performing the operations.
Laurence Gonsalves
Good point; the answer is more intended to open the OP's eyes to such things, rather than to say it is the most efficient way to solve this specific problem; as you say, it's horribly inefficient and introduces huge dependencies if you just want to do this one thing.
Matt J
A: 

Why not use a float or double? A float (on intel chips) is a 32-bit floating-point number, so you wouldn't necessarily need 64 bits for the operation?

rascher
With a 32-bit float you'd necessarily lose some precision, as there are more than 2^32 possible values for d, (and floats have values way outside of d's range, so you're actually wasting some of the few bits you have).
Laurence Gonsalves
+1  A: 

Use a float or double, in floating-point arithmetic, division by zero is allowed, results will be a positive or negative infinity

TStamper
+1  A: 

You can always do an explicit check for overflow on a * b:

long long e = (long long) a * (long long) b;
if (e <= INT_MAX) {
    d = e / c;
} else {
    d = a * (b / c);
}

Of course this only works for non-negative a, b, c. If they can be negative you'll also have to check against INT_MIN.

[Update] You could also check which of a and b is larger and thus loses less precision when divided by c:

if (a >= b) {
    d = a / c * b;
} else {
    d = a * (b / c);
}
Nathan Kitchen
If d = a*(b/c), accusation may be lost.
arsane
That still has the problem that if c > b, you get d = a * 0 (if a * b overflows).
Greg Hewgill
If you want maximum accuracy, you should use more bits or floating-point types. My understanding was that the questioner wanted to know how to get the most accurate possible result while still doing all the operations themselves on ints.
Nathan Kitchen
+3  A: 

For best accuracy/precision you'll want to do your multiplies before your divides. As you imply, you'll want to use something with twice as many bits as an int:

int64_t d = (int64_t) a * (int64_t) b;
d /= c;

You don't need both casts, but they arguably make it a bit clearer.

Note that if c is small enough, then d can still be bigger than an int. That may or may not be an issue for you. If you're sure it isn't you can cast down to an int at the end.

Laurence Gonsalves
I think you are right, I must multiplies before divides
arsane
Don't use long long, use integers with a specific size (e.g. C99's int64_t from stdint.h or if you can't do that do your own typedefs).
starblue
@starblue: that's why I'd said "use the type that's appropriate to your environment", but I wasn't familiar with C99's int64_t. (Prior to C99 everyone just defined their own "n-bit int" types) I've updated the answer to use int64_t as you suggested. Thanks!
Laurence Gonsalves
+1  A: 

For your problem as stated, I'd do d = (long long)a * b / c;

No sense in going to float when you only need more bits. No need to redeclare or cast everything. Casting a is enough to promote b and c to larger size in the expression.

dwc
A: 

I'd do something along the lines of the following:

if(c){
    d = (long long)a * b;
    d /= c;
}
else{
    // some error code because div by 0 is not allowed
}
warren