如何解决双重转换为uint64_t
下面的演示程序演示了一些我不理解的行为。
#include <string>
#include <limits>
#include <iostream>
constexpr double bits64 = 18446744073709551616.0; // 2^64
void diff_hash(double diff)
{
double hash = bits64 / diff;
uint64_t hash_64_1 = hash;
uint64_t hash_64_2 = hash < std::numeric_limits<uint64_t>::max() ? hash : std::numeric_limits<uint64_t>::max();
uint64_t hash_64_3 = std::numeric_limits<uint64_t>::max();
if(hash < hash_64_3){
hash_64_3 = hash;
}
std::cout << "hash_64_1: " << hash_64_1 << "," << "hash_64_2: " << hash_64_2 << "," << "hash_64_3: " << hash_64_3 << std::endl;
}
int main()
{
diff_hash(1);
return 0;
}
输出
hash_64_1: 0,hash_64_2: 0,hash_64_3: 18446744073709551615
问题:
1。)为什么hash_64_1 == 0
?尽管事件分配的值显然是最大64值
2。)为什么hash_64_2 == 0
?我确认如果我将行更改为
uint64_t hash_64_2 = hash < std::numeric_limits<uint64_t>::max() ? hash : std::numeric_limits<uint32_t>::max();
hash_64_2
的最大32个值
链接到Wandbox示例https://wandbox.org/permlink/HyXRX2CiNgIIpYkQ
解决方法
-
18446744073709551616.0 / 1.0
被评估为double
。假定为IEEE754,其值为18446744073709551616.0
。将其转换为超出范围uint64_t
的行为是未定义。这种不确定行为的常见表现是 wrap-around 到0。(这是大多数人认为发生的情况,但是当从超出范围的浮点值转换时,行为是不确定的。) -
使用表达式
hash < std::numeric_limits<uint64_t>::max()
,将右侧隐式转换为double
。但是该数字不能表示为double
,因此会四舍五入到最接近的double
,即18446744073709551616.0
。因此hash_64_2
也为0。
1。)为什么hash_64_1 == 0?尽管事件分配的值显然是最大64值
实际上很难弄清楚。 hash
显然比最大64位值更大。将不确定的(目标类型)浮点转换为整数的行为是不确定的。
“分配的值显然是最大64值”->一对一。
最大uint64_t
值为18446744073709551615
,而不是18446744073709551616
。
看到的效果是由于UB将超出范围的double
转换为uint64_t
而引起的。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。