When I compile this trivial piece of code via Microsoft's VC 2008:
double maxDistance(unsigned long long* a, unsigned long long* b, int n)
{
double maxD = 0, currentD = 0;
for(int i = 0; i < n; ++i)
{
currentD = b[i] - a[i];
if(currentD > maxD)
{
maxD = currentD;
}
}
return maxD;
}
The compiler gives me:
warning C4244 stating: conversion from 'unsigned long long' to 'double', possible loss of data. On the line
currentD = b[i] - a[i]
I know that it's better to rewrite the code somehow, I use double to account for possible negative values of the difference, but I'm just curious, why in the world conversion from unsigned long long to double can lead to data loss if unsigned long long's range is from 0 to 18,446,744,073,709,551,615 and double is +/- 1.7E +/- 308 ?
If you can't avoid them, then add a runtime check to detect whether the value being converted is greater than or equal to zero and less than or equal to the maximum value of the signed type. Values in this range will transfer from signed to unsigned or from unsigned to signed without being reinterpreted.
A double supports a larger range of possible values, but cannot represent all values in that range. Some of the values that cannot be represented are integral values, which a long or a long long can represent.
If the selected conversion is a promotion, the compiler doesn't issue a warning. If the conversion is a narrowing, the compiler issues a warning about possible data loss. Whether actual data loss occurs depends on the actual values involved, but we recommend that you treat this warning as an error.
Because widening conversions are always safe, the compiler performs them silently and doesn't issue warnings. The following conversions are widening conversions. The compiler performs narrowing conversions implicitly, but it warns you about potential data loss.
An IEEE double-precision floating point number has 53 bits of mantissa. This means that (most) integers greater than 253 can't be stored exactly in a double.
Example program (this is for GCC, use %I64u
for MSVC):
#include <stdio.h>
int main() {
unsigned long long ull;
ull = (1ULL << 53) - 1;
printf("%llu %f\n", ull, (double)ull);
ull = (1ULL << 53) + 1;
printf("%llu %f\n", ull, (double)ull);
return 0;
}
Output:
9007199254740991 9007199254740991.000000
9007199254740993 9007199254740992.000000
A double
supports a larger range of possible values, but cannot represent all values in that range. Some of the values that cannot be represented are integral values, which a long
or a long long
can represent.
Trying to assign a value into a floating point variable that it cannot represent means the result is some approximation - a value that is close, but not exactly equal. That represents a potential data loss (depending on what value is being assigned).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With