为什么这段代码,
const float x[16] = { 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8,
1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6};
const float z[16] = {1.123, 1.234, 1.345, 156.467, 1.578, 1.689, 1.790, 1.812,
1.923, 2.034, 2.145, 2.256, 2.367, 2.478, 2.589, 2.690};
float y[16];
for (int i = 0; i < 16; i++)
{
y[i] = x[i];
}
for (int j = 0; j < 9000000; j++)
{
for (int i = 0; i < 16; i++)
{
y[i] *= x[i];
y[i] /= z[i];
y[i] = y[i] + 0.1f; // <--
y[i] = y[i] - 0.1f; // <--
}
}
运行速度比以下位快 10 倍以上(除另有说明外相同)?
const float x[16] = { 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8,
1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6};
const float z[16] = {1.123, 1.234, 1.345, 156.467, 1.578, 1.689, 1.790, 1.812,
1.923, 2.034, 2.145, 2.256, 2.367, 2.478, 2.589, 2.690};
float y[16];
for (int i = 0; i < 16; i++)
{
y[i] = x[i];
}
for (int j = 0; j < 9000000; j++)
{
for (int i = 0; i < 16; i++)
{
y[i] *= x[i];
y[i] /= z[i];
y[i] = y[i] + 0; // <--
y[i] = y[i] - 0; // <--
}
}
使用 Visual Studio 2010 SP1 编译时。优化级别为 -02
sse2
。我没有用其他编译器测试过。
原文由 GlassFish 发布,翻译遵循 CC BY-SA 4.0 许可协议
欢迎来到 非规范化浮点 的世界! 他们可以对性能造成严重破坏!!!
非正规(或次正规)数是一种从浮点表示中获得一些非常接近零的额外值的技巧。非规范化浮点的运算可能比规范化浮点 慢数十到数百倍。这是因为许多处理器不能直接处理它们,必须使用微码捕获和解析它们。
如果在 10,000 次迭代后打印出这些数字,您会看到它们已经收敛到不同的值,具体取决于使用的是
0
还是0.1
。这是在 x64 上编译的测试代码:
输出:
请注意,在第二次运行中,数字非常接近于零。
非规范化数字通常很少见,因此大多数处理器不会尝试有效地处理它们。
为了证明这与非规范化数字有关,如果我们通过将其添加到代码的开头将 非规范化刷新为零:
然后带有
0
的版本不再慢 10 倍,实际上变得更快。 (这要求在启用 SSE 的情况下编译代码。)这意味着我们不是使用这些奇怪的低精度几乎为零的值,而是四舍五入到零。
时序:Core i7 920 @ 3.5 GHz:
最后,这实际上与它是整数还是浮点无关。
0
或0.1f
被转换/存储到两个循环之外的寄存器中。所以这对性能没有影响。