简单的数学运算在 double 上比在 float 数据类型上更快? [复制]
Posted
技术标签:
【中文标题】简单的数学运算在 double 上比在 float 数据类型上更快? [复制]【英文标题】:Simple math operations faster on double than on float datatype? [duplicate] 【发布时间】:2013-01-04 14:26:15 【问题描述】:可能重复:Are doubles faster than floats in c#?
我编写了简单的基准测试来检查在我的应用程序中将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 ***
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);
我得到了这样的结果(发布,无调试,Intel Mobile Core Duo 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 倍。我在这里搜索“双浮动”,我发现了这个:
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
【问题讨论】:
请记住,使用浮点数进行任何冗长的数值计算都有很快累积舍入误差的风险。 You'reNextFloat
与小麦 NextDouble
相比,数字分布非常不同。我不知道这是否有任何关联。但请注意,NextDouble
在0.0
和1.0
之间产生一个数字,它是1.0 / 2147483647.0
的整数倍。因此,数字的“结尾”并不是真正随机的,这在四舍五入计算的乘积或商时可能很重要。
@JeppeStigNielsen 这很重要;看我的回答。当我在修改之前和之后运行 OP 的代码时,将其更改为它们都生成 0 和 1 之间的数字会从根本上改变运行时。
另外,假设您的计算机可以自行乘以 64 位浮点数。要处理 32 位(float
或 System.Single
情况),它可能必须首先“扩大”从数组中读取的数字,然后相乘,最后四舍五入并“缩小”数字以适应结果数组的 32 位“槽”。而 64 位数字则不需要这样的转换。
【参考方案1】:
这与您生成随机数的方式有关。浮点数的乘除并不完全相同;这些数字的实际值很重要。在浮点数的情况下,您要在相当大的范围内填充一个值。如果你创建你的浮点数,使它们在 0 和 1 之间,就像双打一样,那么它会更像你所期望的那样。只需将NextFloat
更改为:
static float NextFloat(Random random)
return (float) random.NextDouble();
我刚刚进行了一些测试,通过这种更改,浮点数的乘法速度提高了 33%。
当然,这只是使比较“公平”的最简单方法。为了更好地了解浮点数与双精度浮点数的真正比较,您需要在各自类型的全部范围内生成随机浮点数和双精度数,或者更好的是,两者都保存代表程序将使用的数据类型的值。
【讨论】:
这是正确的。如果您进行此更改,浮动性能将略好于双倍性能。 不错的收获!修复后的时间:乘法浮点数:107,5963 毫秒乘法双打:132,2323 毫秒除法浮点数:160,1531 毫秒除法双打:170,8343 毫秒。现在这对我来说很有意义。 也许更公平地说:static float NextFloat(Random random) return random.Next(32767) / 32767f;
原因是NextDouble
没有使用double
的完整精度。它只生成1.0 / 2147483647.0
的倍数,即大约十进制数字的精度,而double
的精度大约是十六进制数字。【参考方案2】:
在某些情况下,浮点数上的 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 指令。
【讨论】:
以上是关于简单的数学运算在 double 上比在 float 数据类型上更快? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
HTML5 Canvas 在 Firefox 上比在 Chrome 上更快!为啥?
Java中的简单浮点数类型float和double不能够进行精确运算
为啥 sift.compute() 在 MSER 关键点上比在 SIFT 关键点上慢