我应该使用double还是float?

105

在 C++ 中使用其中一种方法与另一种方法相比,有哪些优缺点?


有人尝试过创建一个浮点数数组和一个双精度浮点数数组,并查看浮点数成员之间是否确实有4个字节,双精度浮点数成员之间是否确实有8个字节吗?可能64位编译器/计算机仍然会为浮点数成员保留8个字节的空间,即使它们不需要那么多。 - user3015682
11个回答

107

如果你想知道真实的答案,你应该阅读计算机科学家关于浮点运算应当了解的内容

简单来说,虽然double在表示精度上更高,但对于某些计算,它会产生更大的误差。正确的选择是:使用恰好所需的精度,而不要过多,并且选择正确的算法。

许多编译器在“非严格”模式下进行扩展浮点数学运算(即使用硬件中可用的更宽的浮点类型,例如80位和128位浮点),这也应考虑在内。实际上,你几乎看不到速度上的任何区别 - 它们本来就是硬件本地支持的。


14
是的。随着现代CPU预取越来越大块的内存,以及并行数值处理单元和流水线结构,速度问题实际上已经不是问题了。如果你需要处理大量数字,那么4字节浮点数和8字节双精度浮点数之间的大小差异或许会对内存占用产生影响。 - lavinio
5
如果您使用SSE(或任何向量浮点单元),单精度浮点数的FLOPS数量将比双精度浮点数多两倍。如果您只使用x87(或任何标量)浮点数,则可能不会有影响。 - Greg Rogers
1
@Greg Rogers:目前编译器并不是那么聪明。除非你在写原始汇编,否则它们之间的差别不大。当然,随着编译器的发展,这种情况可能会改变。 - J-16 SDiZ
@jokoon,浮点数和整个精度/数值稳定性问题领域都不是简单的。 - vonbrand
1
“double会产生更大的误差”?我看了一下(1991)年的论文,除非我读错了,他说舍入误差可能会随着更大的β而增加;但是β不是尾数(精度p在文档中),它是基数...双精度和单精度都有β=2。 - Déjà vu
显示剩余2条评论

56

除非你有特别的理由,否则请使用double。

或许令人惊讶的是,在C(和C ++)中,“正常”的浮点类型是double而不是float。标准数学函数(如sin和log)以double作为参数,并返回double。当你在程序中写下3.14时,普通的浮点字面值具有double类型,而不是float。

在典型现代计算机上,doubles的速度可以与floats一样快,甚至更快,因此性能通常不需要考虑,即使进行大量的计算。(那些必须是大量的计算,否则性能甚至不应该进入你的思维。我的新i7台式电脑可以在一秒钟内执行六十亿个double乘法运算。)


27

由于缺乏上下文,无法回答这个问题。以下是一些可能影响选择的因素:

  1. 浮点数、双精度浮点数和长双精度浮点数的编译器实现。C++标准规定:

    有三种浮点类型:float、double和long double。类型double提供的精度至少与类型float相同,类型long double提供的精度至少与类型double相同。

    因此,所有三种类型在内存中的大小都可能相同。

  2. FPU的存在。并非所有CPU都有FPU,有时会模拟浮点类型,有时则不支持浮点类型。

  3. FPU架构。IA32的FPU内部为80位 - 32位和64位浮点数在加载时扩展为80位,在存储时缩小。还有SIMD可以同时处理四个32位浮点数或两个64位浮点数。SIMD的使用在标准中未定义,因此需要编译器进行更复杂的分析,以确定是否可以使用SIMD,或者需要使用特殊功能(库或intrinsic函数)。80位内部格式的优点是,根据数据何时保存到RAM(从而丢失精度),可能会得到稍微不同的结果。因此,编译器无法特别优化浮点代码。

  • 内存带宽。如果一个双精度数需要比一个浮点数更多的存储空间,那么读取数据就会花费更长的时间。这是一个简单的答案。在现代IA32上,所有这些都取决于数据来自哪里。如果数据在L1缓存中,只要数据来自单个缓存行,负载就可以忽略不计。如果跨越多个缓存行,则存在一些小的开销。如果来自L2,则需要更长的时间,如果在RAM中,则需要更长的时间,最后,如果在磁盘上,则需要很长时间。因此,与数据使用方式相比,选择float或double的重要性较小。如果您想对大量连续数据进行小的计算,则小型数据类型是首选。在小数据集上进行大量计算将允许您使用更大的数据类型而不会产生任何显着影响。如果您随机访问数据,则数据大小的选择无关紧要-数据以页面/缓存行方式加载。因此,即使您只想从RAM获取一个字节,也可能传输32个字节(这非常依赖于系统的架构)。除此之外,CPU/FPU可能是超标量(也称为流水线)的。因此,即使负载需要几个周期,CPU/FPU也可能会忙于执行其他任务(例如乘法),从而在一定程度上隐藏了负载时间。

  • 标准不强制执行任何特定的浮点值格式。

  • 如果您有规格说明,则可以指导您选择最佳选项。否则,就要依靠经验来确定使用什么。


    16

    double更精确,但编码占用8个字节。而float只占用4个字节,所以空间更少、精度也更低。

    如果应用程序中同时使用了double和float,就需要非常小心。我曾经因此遇到过一个bug。代码的某一部分使用了float,而其他部分使用了double。将double复制为float,再将float复制为double可能会导致精度错误,对结果产生重大影响。在我的案例中,那是一个化工厂……幸运的是它没有造成严重后果 :)

    我认为正是由于这种类型的错误,艾琳6号火箭几年前才会爆炸!!!

    仔细考虑要为变量使用哪种类型。


    3
    请注意,浮点数和双精度浮点数的4/8个字节大小并不能保证,在不同平台上大小可能会不同。甚至可能是相同类型... - sleske
    4
    阿丽亚娜5号火箭的代码试图将一个64位浮点数转换为16位有符号整数,其值大于32,767。这导致了一个溢出异常,从而导致火箭启动了自毁序列。涉及到的代码是从一枚旧的、更小的火箭中重用的。 - cmwt

    5

    个人意见,我一直使用双精度,直到遇到一些瓶颈。然后我考虑转换为单精度或优化其他部分。


    4
    这取决于编译器如何实现double。在某些系统上,double和float可以是相同的类型,这是合法的。
    话虽如此,如果它们确实不同,主要问题是精度。由于大小的差异,double具有更高的精度。如果您使用的数字通常超过float的值,则应使用double。
    其他几个人提到了性能问题。这应该是我考虑的最后一个问题。正确性应该是您考虑的第一问题。

    3

    我认为无论有何不同(正如每个人都指出的那样,浮点数占用更少的空间并且通常更快),使用double是否会导致性能问题?我建议使用double... 如果以后你发现“哇,这真的很慢”... 找到你的性能瓶颈(它可能不是你使用double的事实)。然后,如果对于你来说仍然太慢,请看看在哪里可以牺牲一些精度并使用float。


    3

    2

    这取决于CPU,最明显的权衡在于精度和内存之间。有着GB级别的RAM,内存不是什么问题,所以通常最好使用double

    至于性能,这高度依赖于CPU。在32位机器上,float通常比double获得更好的性能。在64位机器上,double有时会更快,因为它(通常)是本地大小。然而,比起数据类型的选择,更重要的是你是否能够利用处理器上的SIMD指令。


    1

    double具有更高的精度,而float占用的内存较少且速度更快。一般来说,除非出现精度不够的情况,否则应使用float。


    6
    在典型的现代计算机上,双精度浮点数(double)与单精度浮点数(float)的速度一样快。 - Thomas Padron-McCarthy

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接