将表示小数的 int 转换为 double 的正确方法是什么
What is the correct way to convert an int with representing a decimal to a double
将表示小数的 int 转换为 double 的正确方法是什么?
我有一个整数,例如 12,123456 表示为 12123456。这来自我无法更改的网络设备。
我想将它转换为 double 且误差最小。
天真的解决方案是:
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%
double res = myint / 1000000.0;
编译器的工作是将 res 设置为最接近的可表示结果值。
请注意,数值对您的意义与您在代码中使用的语言的可用表示形式之间始终存在差异。大多数时候,它并不像本例中那样明显。我想说的是:如果你有一个int
,它的值是12123456
那么这已经是实际值12.123456
的表示了。我可以想象将其转换为 double
的唯一原因是使用浮点运算(尤其是除法),否则我会继续使用 int
。
TL;DR:如果可能的话,我会尽量避免转换。如果你真的想这样做,imho log0 的答案是完全有效的。
将表示小数的 int 转换为 double 的正确方法是什么?
我有一个整数,例如 12,123456 表示为 12123456。这来自我无法更改的网络设备。
我想将它转换为 double 且误差最小。
天真的解决方案是:
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%
double res = myint / 1000000.0;
编译器的工作是将 res 设置为最接近的可表示结果值。
请注意,数值对您的意义与您在代码中使用的语言的可用表示形式之间始终存在差异。大多数时候,它并不像本例中那样明显。我想说的是:如果你有一个int
,它的值是12123456
那么这已经是实际值12.123456
的表示了。我可以想象将其转换为 double
的唯一原因是使用浮点运算(尤其是除法),否则我会继续使用 int
。
TL;DR:如果可能的话,我会尽量避免转换。如果你真的想这样做,imho log0 的答案是完全有效的。