Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why conversion from unsigned long long to double can lead to data loss?

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 ?

like image 234
Dmitry Avatar asked Feb 21 '15 22:02

Dmitry


People also ask

How to avoid errors when converting signed data to unsigned data?

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.

What are the limitations of a double in math?

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.

When does the compiler issue a warning about data loss?

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.

Why does the compiler perform widening conversions silently?

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.


2 Answers

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
like image 109
nwellnhof Avatar answered Oct 08 '22 04:10

nwellnhof


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).

like image 26
Rob Avatar answered Oct 08 '22 04:10

Rob