浮动vs双重表现


91

我做了一些计时测试,还读了一些类似这样的文章(最后评论),在Release build中,float和double值看起来花费了相同的处理时间。

这怎么可能?当float比double值精度低且较小时,CLR如何在相同的处理时间内将double值加倍?


10
我不认为这是完全相同的副本,因为这是在询问其背后的原因,而其他用户在询问它是否实际上更快,但不一定是为什么,
Joan Venge

假设精确地复制了C#中的浮点数是否比浮点数快一倍?(另一位用户于2009年声明)。
彼得·莫滕森

Answers:


153

在x86处理器,至少,float并且double将每一个都可以由FPU进行处理转换成一个10字节的真实。FPU没有针对其支持的不同浮点类型的单独处理单元。

这种古老的建议floatdouble100年前的建议要快,当时大多数CPU没有内置FPU(很少有人拥有单独的FPU芯片),因此大多数浮点运算都是在软件中完成的。在这些机器上(这是由通过熔岩凹坑产生的蒸汽驱动的),它更快地使用float秒。现在,floats 的唯一真正好处是它们占用的空间更少(仅当您拥有数百万个它们时才重要)。


9
也许不是100年前。。。某些FPU支持浮点,双精度和80位级别的本机处理,并且在较短的长度下执行速度更快。有些人实际上也会以较短的长度执行一些较慢的事情... :-)
Brian Knoblauch

4
可能的例外:我认为除法时间取决于位数(1个时钟周期/ 2位)。我对float和double划分的时间似乎与此相符。
尼尔·科菲,

21
请注意SIMD代码-由于您可以将2x浮点数加倍到SIMD寄存器(例如SSE)中的两倍,因此潜在地对浮点数进行操作可能会更快。但是由于它是C#,所以很可能不会发生。
2009年

13
@P Daddy:我想说空间优势在缓存层次结构的每个级别都很重要。当您的一级数据缓存大到16KB并且正在处理4000个数字的数组时,浮点数可能会更快。
Peter G.

4
@artificialidiot永不说永不;)。自4.6起,.NET就开始支持SIMD
ghord 2015年

13

我有一个使用CUDA的小项目,并且我还记得浮点数比那里的两倍还快。一旦主机和设备之间的流量降低(主机是CPU,“正常” RAM,设备是GPU和那里的相应RAM)。但是,即使数据始终驻留在设备上,速度也会变慢。我想我读过某个地方,这种情况最近已经改变,或者应该随着下一代的改变而改变,但是我不确定。

因此,在这种情况下,GPU似乎根本无法固有地处理双精度,这也可以解释为什么通常使用GLFloat而不是GLDouble。

(正如我所说的那样,仅在我想起时,在搜索CPU上的float与double时偶然发现了这一点。)


5
GPU与FPU是完全不同的动物。正如其他人提到的那样,FPU的本机格式是80位双精度。这已经很长时间了。但是,GPU从单精度进入这一领域。它是众所周知的,他们的DP FP(双精度浮点运算)的性能往往正是SP FP性能的一半。似乎他们经常有SP浮点单元,并且他们不得不重用该单元以覆盖双精度。与一个周期相比,它恰好产生两个周期。那是一个巨大的性能差异,当我面对它时令我震惊。
Csaba Toth 2013年

1
一些科学计算需要DP FP,而领先的GPU制造商并没有因此而宣布性能下降。现在他们(AMD,nVidia)在DP和SP主题上似乎有所改进。英特尔至强融核的许多内核都包含奔腾的FPU,并且请注意英特尔强调了它的双精度功能。那才是真正能够与GPGPU怪物竞争的地方。
Csaba Toth 2013年

12

但是,在某些情况下,首选使用浮点数-例如,使用OpenGL编码,更常见的是使用GLFloat数据类型(通常直接映射到16位浮点数),因为在大多数GPU上,它比GLDouble效率更高。


3
也许是由于更高的数据吞吐量?如果您具有数字矩阵(z缓冲区等),则数据大小变得更加重要,并且避免在float和double之间进行转换可以加快处理速度。我猜。
Lucero

2
无疑是吞吐量。同样,在特殊情况下,使用浮点数中的double值不可能获得任何可见的信息,所以为什么要浪费内存-特别是因为GPU上的内存比CPU少
-Cruachan

1
吞吐量以及 SP FP(单精度浮点)比DP FP(双精度)更是GPU内部FPU的本机格式这一事实。请参阅我对@Mene答案的评论。GPU和CPU FPU是非常不同的动物,CPU的FPU在DP FP中正在考虑。
Csaba Toth 2013年


12

它取决于32位64位系统。如果编译为64位,则double会更快。在64位(计算机和操作系统)上编译为32位,使浮动速度提高了约30%:

    public static void doubleTest(int loop)
    {
        Console.Write("double: ");
        for (int i = 0; i < loop; i++)
        {
            double a = 1000, b = 45, c = 12000, d = 2, e = 7, f = 1024;
            a = Math.Sin(a);
            b = Math.Asin(b);
            c = Math.Sqrt(c);
            d = d + d - d + d;
            e = e * e + e * e;
            f = f / f / f / f / f;
        }
    }

    public static void floatTest(int loop)
    {
        Console.Write("float: ");
        for (int i = 0; i < loop; i++)
        {
            float a = 1000, b = 45, c = 12000, d = 2, e = 7, f = 1024;
            a = (float) Math.Sin(a);
            b = (float) Math.Asin(b);
            c = (float) Math.Sqrt(c);
            d = d + d - d + d;
            e = e * e + e * e;
            f = f / f / f / f / f;
        }
    }

    static void Main(string[] args)
    {
        DateTime time = DateTime.Now;
        doubleTest(5 * 1000000);
        Console.WriteLine("milliseconds: " + (DateTime.Now - time).TotalMilliseconds);

        time = DateTime.Now;
        floatTest(5 * 1000000);
        Console.WriteLine("milliseconds: " + (DateTime.Now - time).TotalMilliseconds);

        Thread.Sleep(5000);
    }

2
您是否考虑过那30%可能是因为您使用了额外的演员表?
2014年

@RasmusDamgaardNielsen由于Math使用double,因此强制转换是问题的一部分。但是您误读了我的文章:我的测试表明我的表现更好。
Bitterblue 2014年

2
上面发布的结果是虚假的。我的测试表明,在发布模式下具有.NET 4.0的旧32位计算机上,floatdouble性能实际上是相同的。在许多独立试验中求平均值时,相差不到0.3%,在该试验中,每个试验对连续链接的变量进行乘,除和加法运算(以避免妨碍编译器优化)。我使用Math.Sin()和进行了第二组测试,Math.Sqrt()结果也相同。
Special Sauce 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.