我怎么能相信从double到integer的强制转换
How can I trust casting from double to integer?
我一直在编写一些创建直方图的简单代码,并发现以下代码:
double value = 1.2;
double bucketSize = 0.4;
double bucketId = value / bucketSize;
std::cout << "bucketId as double: " << bucketId << std::endl;
std::cout << "bucketId as int: " << int(bucketId) << std::endl;
结果疯狂输出:
bucketId as double: 3
bucketId as int: 2
这基本上破坏了我对电脑的信任;)当在创建直方图的同时为CCD_ 2寻找右CCD_。
我知道有舍入误差等,但有没有通用的解决方案?
(以防万一)请不要建议在转换为int
之前将0.5
添加到除法结果中,因为在某些情况下(例如double value = 3; double bucketSize = 2;
)显然效果不佳
提前谢谢。
我或多或少是基于你对其他人的一些评论。为了得到整数部分,解决方案是使用modf
。但是1.2 / 0.4
的整数部分很可能是2
,而不是3
;bucketId
0在机器浮点中不可表示(大多数至少是他们),所以你被一个非常接近CCD_ 11。
真正的问题是你到底想要什么。如果你在看根据bucketSize
,则执行此操作的正确方法是使用全方位缩放整数:
int value = 12;
int bucketSize = 4;
int bucketId = value / bucketSize;
然后:
std::cout << "bucketId as double: " << bucketId / 10.0 << std::endl;
std::cout << "bucketId as int: " << bucketId / 10 << std::endl;
否则,如果您想将值保持为双倍,您将必须决定对于到CCD_ 13的转换有多接近,然后使用您自己的功能:
int
asInt( double d )
{
double results;
double frac = modf( d, &results );
if ( frac > 1.0 - yourEpsilonHere ) {
results += 1.0;
}
return results;
}
由您决定什么价值适合yourEpsilonHere
;这取决于应用程序。(一次我用了这个技术,我们用了1E-9
。这并不意味着不过,这对你来说很合适。)
在注释中,您说您想要Integer part of the result
。不幸的是,1.2 / 0.4
的double
结果恰好是2.9999999999999996
(在我的机器上。你可以通过使用value
1看到cout
的确切值),因此结果的整数部分是2
。正如您所知,这是因为并非所有数字都可以用浮点数字表示,而且浮点运算会产生错误。
取浮点数的整数部分与比较相等的浮点数处于同一级别;你不会得到一致的结果。如果必须有精确的结果,通用解决方案是根本不使用浮点数,而是使用不动点。
与等式比较一样,您可以使用适当的ε值来解决此问题。在这种情况下,在取整数部分之前,您可以将一个非常小的浮点数添加到结果中(如果为负数,则可以减去)。添加的数字必须大于该数字可能存在的最大误差,但小于您必须支持的最小精度数字(因此,如果您必须支持0.001精度,则9.999不会变为10)。计算出一个好的数字可能相当困难。
使用std::lround
。它返回与您的双位数最接近的整数。
#include<numeric>
double value = 1.2;
double bucketSize = 0.4;
double bucketId = value / bucketSize;
std::cout << "bucketId as int: " << std::lround(bucketId) << std::endl;
请注意,3.0/2.0
仍然可能导致意外的结果,这取决于结果是1.4999998
还是1.5000001
。
也许是固定的十进制近似?
(int)(value * 100)/(int)(bucketSize *100)
如果要在0.25之前返回下一个数字(如(double)1.75
到(int)2
),请使用int(floor(buckedId+0.25))
。
问题是你想把它四舍五入到上一个数字的多少。
#include<iostream>
#include <limits>
int main()
{
double value = 1.200000000000000;
double bucketSize = 0.4000000000000000;
double bucketId = value / bucketSize;
std::cout.precision(16);
std::cout << "bucketId as double: " << std::fixed << bucketId << std::endl;
std::cout << "bucketId as int: " << int(bucketId) << std::endl;
return 1;
}
在你的系统上试试这个——你想要
bucketId为双:2.9999999999999996
bucketId为int:2
与相比
std::cout.precision(15);
你会
bucketId为双:3.000000000000000
bucketId为int:2
之所以会发生这种情况,是因为double的精度限制是15,你也可以尝试设计长double并改变精度。
我建议一些类似的东西
double d = 1.4 / 0.4;
int whole = (int)d;
int nextWhole = whole + 1;
int result = whole;
if (fabs(d - nextWhole) < EPSILON) result = nextWhole;
(这适用于正数)
基本上,如果你的数字非常接近下一个整数,那么这段代码将使用下一个整型。
您可以使用round()
http://www.cplusplus.com/reference/cmath/round/
我相信这总是让0.5个数字远离零,所以如果这对你的情况不好,它可能不是最佳解决方案
- 防止主数据类型C++的隐式转换
- 模板参数替换失败,并且未完成隐式转换
- 努力将整数转换为链表。不知道我在这里做错了什么
- 将Integer转换为4字节的unsined字符矢量(按大端字节顺序)
- 将cryptopp :: Integer转换为lpctstr
- 从 cryptopp::integer 转换为 QString
- 将Integer转换为Little Endian十六进制字符串
- 将Integer转换回SecByteBlock
- 如何以可移植的方式将integer转换为little-endian
- integer可以被类型转换为指向integer的指针
- 我怎么能相信从double到integer的强制转换
- 如何将Integer句柄转换为HWND
- 如何将 CryptoPP::Integer 转换为 char*
- boost::multiprecision从integer转换为cpp_dec_foat编译错误
- C++、Integer和Char数组转换故障
- 整数到char*和char*到Integer的转换
- 在C++中,键入将结构强制转换为integer,反之亦然
- 将std::string转换为integer时,如何处理上溢/下溢
- 将integer转换为函数参数的字符串
- 键入强制转换为integer