Home > Software design >  C unsigned long with casting not adding correctly
C unsigned long with casting not adding correctly

Time:04-28

I can't get the correct value of 15136704000 for the third print line and I am not sure what the issue is. It works correctly when compiled via gcc on Linux but Windows keeps spitting out nonsense and I just would like to understand why.
Windows displays it as Which is 2251802112 inches away.

#include <stdio.h>

int main(void)
{
    const int five = 5;
    const int eight = 8;
    const int mi_to_in = 63360;

    int miles_to_moon = 238900;
    int km_to_moon = (float) eight / five * miles_to_moon;
    unsigned long inches_to_moon = (long) miles_to_moon * mi_to_in;

    printf("The moon is %d miles away.\n", miles_to_moon);
    printf("Which is equivalent to %d kilometers away.\n", km_to_moon);
    printf("Which is %lu inches away.\n", inches_to_moon);
}

CodePudding user response:

As commented by @jamesdlin, the expression (long)miles_to_moon * mi_to_in causes an arithmetic overflow on Windows because the type long only has 32 bits on this system, including on its 64-bit version. Using unsigned long long for this computation would solve the problem, and you should actually use long for mi_to_in and miles_to_moon for portability to some systems.

The C Standard provides fixed length integer types such as int32_t and int64_t defined in <stdin.h> on systems that support them. These types could be used for these variables with the proper range, but for better portability and simplicity, you should use double for such computations:

#include <stdio.h>

int main() {
    double mi_to_in = 63360;    /* exact figure */
    double mi_to_km = 1.60934;  /* exact figure */

    double miles_to_moon = 238900;  /* average distance approximation */
    double km_to_moon = miles_to_moon * mi_to_km;
    double inches_to_moon = miles_to_moon * mi_to_in;

    printf("The moon is %.0f miles away.\n", miles_to_moon);
    printf("Which is equivalent to %.0f kilometers away.\n", km_to_moon);
    printf("Which is %.0f inches away.\n", inches_to_moon);
    return 0;
}

Output:

The moon is 238900 miles away.
Which is equivalent to 384471 kilometers away.
Which is 15136704000 inches away.

Note however that multiplying an approximate figure by an exact one does not increase the precision, which the number of significant digits in the above output might suggest. Rounding these figures seems preferable, yet this would produce 384500 km, which is not the commonly used figure 384400 km.

A more precise average semi-axis is 384399 km, approximately 238855 miles, commonly converted to 238900 mi.

Rounding to a specified number of significant digits is not simple and there is no standard function in the C library to do it. You can use snprintf with %.3e to produce the digits in exponential format, and convert back using strtod, but is cumbersome and inefficient.

  • Related