我编写了简单的基准测试来检查我的应用程序中可以将double
数据类型更改为float
的性能。这是我的代码:
// my form:
// one textbox: textbox1 (MultiLine property set to true)
// one button: button1 with event button1_Click
private void button1_Click(object sender, EventArgs e)
{
int num = 10000000;
float[] floats1 = new float[num];
float[] floats2 = new float[num];
float[] floatsr = new float[num]; // array for results
double[] doubles1 = new double[num];
double[] doubles2 = new double[num];
double[] doublesr = new double[num]; // array for results
Stopwatch stw = new Stopwatch();
log("Preparing data");
Random rnd = new Random();
stw.Start();
for (int i = 0; i < num; i++)
{
floats1[i] = NextFloat(rnd);
floats2[i] = NextFloat(rnd);
doubles1[i] = rnd.NextDouble();
doubles2[i] = rnd.NextDouble();
}
stw.Stop();
log(stw.Elapsed.TotalMilliseconds.ToString()+"ms");
stw.Reset();
log("");
stw.Start();
for (int i = 0; i <# i++)
{
floatsr[i] = floats1[i] * floats2[i];
}
stw.Stop();
log("Multiplying floats: " + stw.Elapsed.TotalMilliseconds.ToString() + "ms");
stw.Reset();
stw.Start();
for (int i = 0; i < num; i++)
{
doublesr[i] = doubles1[i] * doubles2[i];
}
stw.Stop();
log("Multiplying doubles: " + stw.Elapsed.TotalMilliseconds.ToString() + "ms");
stw.Reset();
stw.Start();
for (int i = 0; i < num; i++)
{
floatsr[i] = floats1[i] / floats2[i];
}
stw.Stop();
log("Dividing floats: " + stw.Elapsed.TotalMilliseconds.ToString() + "ms");
stw.Reset();
stw.Start();
for (int i = 0; i < num; i++)
{
doublesr[i] = doubles1[i] / doubles2[i];
}
stw.Stop();
log("Dividing doubles: " + stw.Elapsed.TotalMilliseconds.ToString() + "ms");
stw.Reset();
}
private void log(string text)
{
textBox1.Text = textBox1.Text + text + Environment.NewLine;
}
// I found that function somewhere on stackoverflow
static float NextFloat(Random random)
{
double mantissa = (random.NextDouble() * 2.0) - 1.0;
double exponent = Math.Pow(2.0, random.Next(-126, 128));
return (float)(mantissa * exponent);
}
我得到了这样的结果(发布,没有调试,英特尔移动酷睿双核T2500 2.0GHz 2MB CPU):
Preparing data 5275,6862ms
Multiplying floats: 442,7865ms
Multiplying doubles: 169,4028ms
Dividing floats: 550,7052ms
Dividing doubles: 164,1607ms
我很惊讶,double
上的操作几乎比float
上的操作快3倍。我在这里搜索了“double float”,我发现了这个:
Is using double faster than float?
最佳答案主要集中在CPU架构上,但我不同意这一点。
我怀疑其他东西导致浮点数性能低下,因为我的带有英特尔SSE的CPU应该能够一次乘法或除4浮点数(打包浮点指令),或者一次加倍2次。所以花车应该更快。
也许编译器(或.net中的clr)以某种方式优化内存使用?
有没有办法优化它并使浮动更快?
请不要报告重复,我看到其他问题但他们不满意我。
我改变生成花车的方法后的结果现在看起来很好(Servy建议):
Preparing data 1367,0678ms
Multiplying floats: 109,8742ms
Multiplying doubles: 149,9555ms
Dividing floats: 167,0079ms
Dividing doubles: 168,6821ms
答案 0 :(得分:6)
它与你如何生成随机数有关。浮点数的乘法和除法并不完全相同;这些数字的实际值很重要。在浮点数的情况下,您将在相当大的范围内填充值。如果你创建你的花车,使它们介于0和1之间,就像双打一样,那么它会更像你期望的那样。只需将NextFloat
更改为:
static float NextFloat(Random random)
{
return (float) random.NextDouble();
}
我刚刚进行了一些测试,并且通过该更改,浮点数在乘法时的速度提高了33%。
当然,这只是使比较“公平”的最简单方法。为了更好地理解浮点数与双精度数的比较,你需要生成随机浮点数,并在各个类型的整个范围之间加倍,或者更好的是,两个保持值代表程序将使用的数据类型。
答案 1 :(得分:4)
浮点数上的GPU操作仍然更快,在某些情况下到目前为止,因为它们具有32位浮点硬件。
您的x86(或x86_64)架构CPU在数学协处理器中没有32位支持。甚至64位支持。 x87浮点单元使用80位算术。
现在,现代x86 CPU确实具有SIMD指令(MMX,SSE,AVX),其硬件支持32位和64位浮点运算,具有更高的性能 - 如果您可以在SIMD单元中执行所有操作。在SIMD和FPU之间移动数据会降低性能。
从当前版本开始,.NET不使用MMX或SSE或AVX。您可以尝试使用Mono,它提供JIT编译为SIMD指令的内部方法。或者您可以将本机代码用于性能最敏感的部分,因为现代C ++编译器不仅允许使用SIMD,而且可以将看似普通的代码自动矢量化为SIMD指令。