我最近遇到了一些代码,它有一个循环的形式
for (int i = 0; i < 1e7; i++){
}
Run Code Online (Sandbox Code Playgroud)
我怀疑这样做的智慧,因为1e7是浮点类型,并且i在评估停止条件时会促使它被提升.这应该引起关注吗?
Bat*_*eba 50
这里房间里的大象是a的范围int 可以小到-32767到+32767,并且为此分配比这更大的值的行为int是未定义的.
但是,至于你的要点,确实应该关注你,因为这是一个非常坏的习惯.事情可能会出错,1e7是浮点双重类型.
i由于类型提升规则而将转换为浮点的事实有点没有实际意义:如果意外截断明显的整数文字,则会发生真正的损坏.通过"示例证明"的方式,首先考虑循环
for (std::uint64_t i = std::numeric_limits<std::uint64_t>::max() - 1024; i ++< 18446744073709551615ULL; ){
std::cout << i << "\n";
}
Run Code Online (Sandbox Code Playgroud)
i如您所料,这将输出范围内的每个连续值.注意std::numeric_limits<std::uint64_t>::max()是18446744073709551615ULL,这比2的64次方(这里我用幻灯片般的"经营者"少1 ++<一起工作时,这是非常有用unsigned的类型.很多人认为-->,并++<为混淆,但在科学规划,他们是共同的,特别是-->.)
现在在我的机器上,double是一个IEEE754 64位浮点.(例如,方案特别擅长于精确表示2的幂 - IEEE754可以精确地表示2到1022的幂.)因此18,446,744,073,709,551,616(2的64次幂)可以精确地表示为double.之前最接近的可表示数字18,446,744,073,709,550,592(减少1024).
所以现在让我们把循环写成
for (std::uint64_t i = std::numeric_limits<std::uint64_t>::max() - 1024; i ++< 1.8446744073709551615e19; ){
std::cout << i << "\n";
}
Run Code Online (Sandbox Code Playgroud)
在我的机器上只输出一个值i:( 18,446,744,073,709,550,592我们已经看过的数字).这证明这1.8446744073709551615e19是一种浮点类型.如果允许编译器将文字视为整数类型,则两个循环的输出将是等效的.
Fra*_*fer 14
它会工作,假设你int的至少是32位.
但是,如果你真的想使用指数表示法,最好在循环外定义一个整数常量并使用正确的强制转换,如下所示:
const int MAX_INDEX = static_cast<int>(1.0e7);
...
for (int i = 0; i < MAX_INDEX; i++) {
...
}
Run Code Online (Sandbox Code Playgroud)
考虑到这一点,我想说写起来要好得多
const int MAX_INDEX = 10000000;
Run Code Online (Sandbox Code Playgroud)
或者如果你可以使用C++ 14
const int MAX_INDEX = 10'000'000;
Run Code Online (Sandbox Code Playgroud)
Che*_*Alf 10
1e7是类型的文字double,通常double是64位IEEE 754格式,带有52位尾数.大致的2每第十功率对应于10的第三功率,所以double应能代表整数高达至少10 5*3 = 10 15,准确.如果int是32位,那么int大约有10 3*3 = 10 9作为最大值(要求谷歌搜索它说"2**31 - 1"= 2 147 483 647,即粗略估计的两倍).
因此,在实践中,它在当前桌面系统和更大的桌面系统上是安全的.
但是C++只允许int16位,而在例如具有那么小的嵌入式系统上,int可能会有未定义的行为.