akaltar
akaltar

Reputation: 1107

What is the correct way to convert an int with representing a decimal to a double

What is the correct way to convert an int with representing a decimal to a double?

I have an int representing for example 12,123456 as 12123456. This comes from a network device that I cannot change.

I want to convert it to double with minimal error.

The naive solution would be: double res = boost::numeric_cast<double>(myint) / 1000000.0;

I think that converting myint(a huge number) to a double is more lossy than some other method because the resulting value is near 1 where dobule has more precision.

I am looking for what the least lossy method of doing this conversion is.


EDIT:

I didn't believe log0's answer was right. TL;DR He is.

The test I used:

#include <iostream>
#include <limits>

#include <boost/random.hpp>


inline double DecimalToDouble( int64_t value, int64_t divisor )
{
    int64_t first =  value / divisor;
    int64_t second = value % divisor;

    return (double)first + (double)second / (double)divisor;
}

int main()
{
    boost::mt19937 rng;
    boost::uniform_int<int> distr( std::numeric_limits<int>::min(),
        std::numeric_limits<int>::max() );
    boost::variate_generator< boost::mt19937, boost::uniform_int<> > dice( rng, distr );

    int erra = 0;
    int errb = 0;
    std::cout.precision( std::numeric_limits<double>::max_digits10 );

    int iterations = 1000000;
    for( int i = 0; i < iterations; ++i )
    {
        int x = dice();

        double divi = 10000000.0;

        double a = x / divi;
        double b = DecimalToDouble( x, 10000000 );

        if( (int)(a * divi) != x )
        {

            //std::cout << "ERROR AT A:" << x << '\t' << a << '\t' << b << std::endl;
            erra++;
        }

        if( (int)(b * divi) != x )
        {
            //std::cout << "ERROR AT B:" << x << '\t'  << a << '\t' << b << std::endl;
            errb++;
        }
    }

    std::cout.precision( 10 );
    std::cout << "A:" << (erra / (double)iterations) * 100.0 << "% B:"
            << (errb / (double)iterations) * 100.0 << "%" << std::endl;


    char stop;
    std::cin >> stop;
}

Result on Win7x64 VS2010: A:6.4997% B:6.5188%

Upvotes: 1

Views: 127

Answers (2)

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 123440

Note that there is always a difference between what a numerical value means for you and what representation available from the language you use in your code. Most of the time it is just not as obvious as in this case. What I want to say is: If you have an int whose value is 12123456 then this is already a representation of the actual value 12.123456. The only reason I could imagine to convert it to a double is to use floating point arithmetics (especially division) otherwise I would just stay with the int.

TL;DR: If possible I would try to avoid the conversion. If you really want to do it, imho log0's answer is perfectly valid.

Upvotes: 1

log0
log0

Reputation: 10947

double res = myint / 1000000.0;

That's the job of the compiler to set res to the closest representable value of the result.

Upvotes: 3

Related Questions