Unable to get percentage with 'int' even though value is within range. Works with 'long' though. Why?

101 views Asked by At

Can anyone explain to me why is util2=49, but util1=5?

Program:

#include <stdio.h>

int main()
{
int load1 = 47759534;
int capacity1 = 96000000;

long load2 = 47759534;
int capacity2 = 96000000;

int util1 = (100*load1)/capacity1;
int util2 = (100*load2)/capacity2;

printf("util1 = %d\n", util1);
printf("util2 = %d\n", util2);

return 0;
}

Output:

util1 = 5
util2 = 49

I understand that 'int' is at least 16 bits and 'long' is at least 32 bits but load1 in the above snippet is within the common range of int and long, i.e, 2,147,483,647. Why is util1 rounded off to 5 then?

2

There are 2 answers

4
Emmanuel Herrera On

In C, int is usually 32 bits. Let's assume that is the case here. When you multiply by 100, the result in binary is:

000100011100101010110100001111111000

Since that is more than 32 bits, the most significant bits get discarded. If you take the lowest 32 bit you get 00011100101010110100001111111000 = 480,986,104

If you divide that by 96000000 you'll get 5.

0
chux - Reinstate Monica On

to get percentage

  • Make certain the multiply does not overflow - which is undefined behavior (UB) with signed integers. int is at least 16-bit. long is at least 32-bit. long long is at least 64-bit. Since 47759534 * 100 is a 33-bit product, use at least 64-bit math.
    // int util1 = (100*load1)/capacity1;
    long long util1 = (100LL*load1)/capacity1;
    // printf("util1 = %d\n", util1);
    printf("util1 = %lld\n", util1);
  • Integer division truncates. To get a rounded answer, for positive numbers, add half the divisor, then divide
    long long util1 = (100LL*load1 + capacity1/2)/capacity1;
    printf("util1 = %lld\n", util1);

Advanced: To handle negatives, mixed signed dividend/divisors and rounding ties to even can still use integer math, yet needs more code.