在我看到的大多数代码中,即使不需要高精度,double
仍然比float
更受欢迎。
由于使用双精度类型(CPU / GPU / 内存 / 总线 / 缓存等)存在性能惩罚,那么为什么会过度使用双精度?
例如:在计算流体力学中,我所用的所有软件都使用双精度。在这种情况下,高精度是无用的(因为数学模型中的近似误差),并且有大量数据需要移动,使用浮点数可以减少一半数据量。
今天计算机性能强大无意义,因为它们被用来解决越来越复杂的问题。
在我看到的大多数代码中,即使不需要高精度,double
仍然比float
更受欢迎。
由于使用双精度类型(CPU / GPU / 内存 / 总线 / 缓存等)存在性能惩罚,那么为什么会过度使用双精度?
例如:在计算流体力学中,我所用的所有软件都使用双精度。在这种情况下,高精度是无用的(因为数学模型中的近似误差),并且有大量数据需要移动,使用浮点数可以减少一半数据量。
今天计算机性能强大无意义,因为它们被用来解决越来越复杂的问题。
其中包括:
但最终,你的情况可能有所不同:要自行衡量、测试和决策。
顺便说一句:对于性能狂热者来说甚至还有更多:使用IEEE半精度类型。虽然很少有硬件或编译器支持,但它可以再次将带宽要求减半。
double
在C语言中是一种“自然”的浮点类型,这也影响了C++。请考虑以下事实:
13.9
这样的未加修饰的普通浮点常量具有double
类型。要使它成为float
,我们必须添加额外的后缀f
或F
。float
函数参数*转换为double
:当没有声明存在于参数时,如函数被声明为可变参数(例如printf
)或不存在声明时(旧式C,在C++中不允许)会发生这种情况。printf
的%f
转换说明符接受double
参数而不是float
。没有专门的方法打印float
;float
参数默认提升为double
,因此与%f
匹配。在现代硬件上,float
和double
通常分别映射到32位和64位IEEE 754类型。硬件使用64位值“本地”:浮点寄存器宽度为64位,并且操作是围绕更精确的类型构建的(或者在内部可能比那还要精确)。由于double
映射到该类型,因此它是“自然”的浮点类型。
float
的精度对于任何严格的数值计算工作来说都很差,并且缩小的范围也可能成为问题。IEEE 32位类型仅具有23位的尾数(8位被指数字段消耗掉,一位用于符号)。如果在给定的应用程序中精度和范围的损失不是问题,则float
类型可用于保存大型浮点值数组中的存储。例如,在音频中使用32位浮点值来表示样本。
使用64位类型比32位类型可以将原始内存带宽翻倍,这是真的。然而,这只影响那些具有大量数据数组且访问模式显示出低局部性的程序。64位浮点类型的卓越精度胜过优化问题。根据“先正确再快速”的原则,数值结果的质量比运行时间更重要。
*请注意,不存在从float
表达式到double
的普遍自动提升;该类唯一的提升是整数提升:char
、short
和位域转换为int
。
在我看来,迄今为止的回答并没有真正传达出正确的观点,因此我来试试。
简短的答案是C++开发者使用double而不是float:
虽然大多数FPU的内部表示比32位浮点数或64位双精度浮点数表示更宽,因此在单个计算上双精度浮点数可能与单精度浮点数一样快。
但这只是整个情况的一小部分。现在,如果您在缓存/内存带宽上受到限制,则操作优化就毫无意义。
以下是为什么有些开发人员寻求优化其代码应该考虑使用32位浮点数而不是64位双精度浮点数的原因:
总的来说,我遇到的大多数开发人员对浮点数如何工作真的缺乏了解。因此,我并不惊讶大多数开发人员盲目地使用double。
这主要取决于硬件,但是请注意,最常见的CPU(基于x86 / x87)具有在80位浮点精度上运行的内部FPU(超过浮点数和双倍精度)。
如果您必须在内存中存储一些中间计算,双精度对于内部精度和外部空间来说是不错的平均值。在单个值上,性能更多或少相同。 在大型数字管道上,它可能会受到内存带宽的影响(因为它们将具有双倍长度)。
请注意,浮点数的精度约为6个小数位。 在N立方复杂度问题(例如矩阵反演或变换)中,mul
和div
会损失两到三个数字,只剩下3个有效数字。在1920像素宽的显示器上,它们根本不够用(您需要至少5个有效数字才能正确匹配一个像素)。
这大致使双精度更可取。
通常情况下,即使需要进行大量数字分析才能确定float足够使用,但判断double是否足够使用通常相对容易。这样可以节省开发成本,并避免在分析不正确的情况下出现错误结果。
此外,使用float带来的性能提升通常比使用double更微小,因为大多数流行的处理器都使用一种甚至比double更宽的格式进行浮点运算。
我认为更高的精度是唯一的原因。实际上,大多数人并不会过多考虑,他们只使用双精度。
我认为如果浮点精度对于特定任务已经足够好了,那么没有理由使用双精度。
float
,你可能会抱怨说"即使不需要高性能"。 - Karoly Horvathdouble
已经被实现但float
没有的意思,但这是不正确的。旧的FPU指令使用80位双扩展数字,既不是float
也不是double
,但这并不重要:它可以加载和保存浮点数和双精度浮点数,而没有性能惩罚(或许具有讽刺意味的是,加载/保存80位浮点数的指令是慢的)。在非古老的x86系统上,浮点数和双精度浮点数都直接使用SSE(2)实现。 - harold