将表示小数的int转换为double的正确方法是什么?
我有一个int代表例如12,123456为12123456.这来自一个我无法改变的网络设备。
我希望将其转换为双倍且误差最小。
天真的解决方案是:
double res = boost::numeric_cast<double>(myint) / 1000000.0;
我认为将myint(一个巨大的数字)转换为double比其他方法更有损,因为结果值接近1,dobule的精度更高。
我正在寻找进行此转换的最小损失方法。
编辑:
我不相信log0的答案是对的。 TL; DR 他是。
我使用的测试:
#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;
}
Win7x64 VS2010上的结果:A:6.4997%B:6.5188%
答案 0 :(得分:3)
double res = myint / 1000000.0;
编译器的工作是将res设置为结果的最接近的可表示值。
答案 1 :(得分:1)
请注意,数值对您来说意味着什么,以及您在代码中使用的语言可用的表示形式之间总是存在差异。大多数情况下,它并不像在这种情况下那么明显。我想说的是:如果您的int
值为12123456
,那么这已经是实际值12.123456
的表示。我可以想象将它转换为double
的唯一原因是使用浮点算术(特别是除法),否则我会留在int
。
TL; DR:如果可能,我会尽量避免转换。如果你真的想这样做,imho log0的答案是完全有效的。