在我到过的每个地方,它都说double在几乎所有方面都优于floatfloat已被Java中的double淘汰,所以为什么仍要使用它?

我用Libgdx编写了大量程序,它们迫使您使用float(deltaTime等),但似乎我知道double在存储和内存方面更容易使用。

我还阅读了何时使用float和何时使用double,但是float确实仅适用于带有数字的数字小数点后有很多数字,那么为什么我们不能仅使用double的众多变体之一?

是否有任何理由说明人们为什么坚持使用浮点数,即使它没有真的有什么优势了吗?更改所有内容是否需要太多工作?

评论

何时使用float和何时使用double的可能重复项

您是如何从该问题的答案中推断出“浮点数实际上仅对小数点后有很多数字的数字有好处”?他们说直接相反!

@Eames注意它说的是“数字”,而不是“数字”。当需要精度或范围时,浮点会更糟,而在需要大量不太精确的数据时,浮点会更好。这些答案就是这些。

为什么在长的时候我们有字节,短和整型?

一个更合适的问题是“为什么要从具有数十年代码而无缘无故地中断的语言中删除关键字和原始数据类型?”

#1 楼

LibGDX是主要用于游戏开发的框架。

在游戏开发中,您通常必须实时进行大量的数字运算,而任何性能都可以得到解决。这就是为什么游戏开发人员通常在浮点精度足够好时才使用浮点。

在这种情况下,并不是唯一需要考虑CPU中FPU寄存器的大小。实际上,游戏开发中大部分繁琐的工作都是由GPU完成的,GPU通常针对浮动而不是加倍进行优化。

然后还有:


内存总线带宽(可以在RAM,CPU和GPU之间交换数据的速度)
CPU高速缓存(这使得以前的工作不再需要)
RAM
VRAM

这些都是宝贵的资源,使用32位float而不是64bit double时,它们的资源将增加两倍。

评论


谢谢!这确实有帮助,因为您深入了解了内存使用量的变化以及原因

– Eames
16年4月26日在21:06

同样,对于SIMD操作,32位值可以具有两倍的吞吐量。正如8bittree的答案所指出的那样,GPU具有更高的性能损失和双精度。

– Paul A. Clayton
16-4-27的2:20

许多图形流水线甚至支持16位半浮点数,以在精度足够的情况下提高性能。

–阿迪·沙维特(Adi Shavit)
16年4月27日在9:48

@phresnel都是。您必须移动位置,更新数据,什么都不要。这是简单的部分。然后,您必须渲染(=读取,旋转,缩放和平移)纹理,距离,并将其转换为屏幕格式……要做的事情很多。

– Sebb
16年4月27日在13:05

@phresnel是游戏开发企业的前运营副总裁,我向您保证,几乎每个游戏都有大量的数字运算。请注意,它通常包含在库中,并且100%从工程师那里抽象出来,我希望他们理解并尊重所有处理工作。魔术反平方根,有人吗?

– corsiKa
16-4-27的16:41

#2 楼

浮点型使用的内存是双精度型的一半。

它们的精度可能比双精度型低,但是许多应用程序并不需要精度。它们的范围比任何类似大小的定点格式大。因此,它们填补了一个利基市场,该利基市场需要广泛的数字范围,但不需要高精度,并且内存使用率很重要。例如,我过去曾将它们用于大型神经网络系统。

移动到Java之外,它们还广泛用于3D图形中,因为许多GPU都将它们用作其主要格式-在非常昂贵的NVIDIA Tesla / AMD FirePro设备之外,GPU上的双精度浮点运算非常慢。

评论


说到神经网络,由于越来越多地使用加速器进行机器学习,CUDA目前支持半精度(16位)浮点变量,精度甚至更低,但内存占用量更低。

– JAB
16-4-26在22:08



而且,当您对FPGA进行编程时,您倾向于每次:v都手动选择尾数和指数的位数。

– Sebi
16年4月28日在13:04

#3 楼

向后兼容性
这是将行为保持在已经存在的语言/库/ ISA / etc中的第一原因。考虑如果将它们从Java中浮出水面会发生什么。 Libgdx(以及成千上万的其他库和程序)无法正常工作。要更新所有内容,将需要大量的精力,对于许多项目而言,可能要花费数年的时间(只需看看向后兼容性突破的Python 2到Python 3的过渡)。并不是所有的东西都会被更新,某些东西会永远被破坏,因为维护者放弃了它们,也许比他们早了,因为他们花费了比他们想要更新更多的精力,或者因为不再可能完成他们应有的软件
性能
64位双精度占用的内存是两倍,并且处理速度通常总是比32位浮点运算慢(非常罕见的例外是,预计将很少使用或不使用32位浮点运算能力Libgdx是一个游戏库,与您特别相关,除非您是专门为特殊的硬件而开发,否则在不久的将来您将不会再遇到这种情况。
与您特别相关的Libgdx是一个游戏库。与大多数软件相比,游戏倾向于对性能更加敏感。游戏图形卡(即AMD Radeon和NVIDIA Geforce,而不是FirePro或Quadro)往往具有非常弱的64位浮点性能。由Anandtech提供,以下是在AMD和NVIDIA的一些顶级游戏卡上(截至2016年初)双精度性能与单精度性能的比较方法。
 AMD
Card    R9 Fury X      R9 Fury       R9 290X    R9 290
FP64    1/16           1/16          1/8        1/8

NVIDIA
Card    GTX Titan X    GTX 980 Ti    GTX 980    GTX 780 Ti
FP64    1/32           1/32          1/32       1/24
 

请注意,R9 Fury和GTX 900系列比R9 200和GTX 700系列更新,因此64位浮点的相对性能正在下降。回到足够远的地方,您会发现GTX 580的比率是R9 200系列的1/8。
如果您有严格的时间限制并且使用较大的Double不能获得太大收益,则需要付出1/32的性能代价。

评论


请注意,由于32位指令的优化程度越来越高,因此64位浮点的性能相对于32位性能有所下降,而不是因为实际的64位性能正在下降。它还取决于所使用的实际基准;我不知道这些基准测试中突出显示的32位性能缺陷是否是由于内存带宽问题以及实际的计算速度引起的

– sig_seg_v
16年4月26日在22:35

如果您要谈论图形卡中的DP性能,则绝​​对应该提及Titan / Titan Black。这两个功能模块均允许卡达到1/3的性能,但以单精度性能为代价。

– SGR
16 Apr 27'8:32



@sig_seg_v肯定至少在某些情况下64位性能会绝对下降,而不仅仅是相对下降。查看这些结果以获取双精度Folding @ Home基准,其中GTX 780 Ti击败了GTX 1080(另一张1/32比例的显卡)和980 Ti,而在AMD方面,则是7970(一张1/4比例的显卡)以及R9 290和R9 290X都击败了R9 Fury系列。将其与基准的单精度版本进行比较,在基准版本中,较新的卡均轻而易举地胜过其前代产品。

– 8bittree
16年7月26日在0:12

#4 楼

原子操作

除了其他人已经说过的,double(和long)特定于Java的缺点是不能保证对64位基本类型的赋值是原子的。从Java SE 8版的Java语言规范中,第660页(添加了重点):


17.7 doublelong的非原子处理

在Java编程语言内存模型的基础上,对非易失性longdouble值的单次写入被视为两次单独的写入:一次写入每个32位的一半。这可能导致线程在一次写入中看到64位值的前32位,而在另一次写入中看到后32位。


糟糕。

为避免这种情况,您必须使用volatile关键字声明64位变量,或在分配周围使用其他某种形式的同步。

评论


您是否不需要以任何方式同步对int和float的并发访问以防止丢失更新并使它们易失以防止过度缓存?我是否认为int / float原子性只能阻止它们永远不包含不应有的“混合”值,这是我的错吗?

–Traubenfuchs
16年4月28日在11:33

@Traubenfuchs也就是说,确实可以保证在那里。我听说过这个词很“撕裂”,我认为它很好地体现了这种效果。 Java编程语言模型保证在读取32位值时,该值将在某个时刻写入它们。这是令人惊讶的宝贵保证。

–Cort Ammon
16年4月28日在23:54

关于原子性的这一点非常重要。哇,我忘了这个重要事实。我们可能倾向于认为原始元素本质上是原子的,这是违反直觉的。但在这种情况下不是原子的。

–罗勒·布尔克
16-4-30在3:14



#5 楼

似乎其他答案错过了一个重要点:SIMD体系结构可以处理更少/更多的数据,具体取决于它们是在double还是float结构上运行(例如,一次八个浮点值,一次四个四个double值)。 >性能注意事项摘要


float在某些CPU(例如某些移动设备)上可能更快。

float使用较少的内存,因此在庞大的数据集中可能会大大减少所需的总内存(硬盘/ RAM)和所消耗的带宽。

float可能会导致CPU消耗更少的功率(我找不到参考,但至少不可能看似合理)对于单精度计算,与双精度计算相比。
float消耗更少的带宽,并且在某些应用中很重要。
SIMD架构可能处理两倍于相同数量的数据,因为通常。

float使用的高速缓存内存是原来的一半加倍。

精度注意事项摘要

在许多应用中,float足够了

double仍然具有更高的精度

兼容性注意事项

如果必须将数据提交给GPU(例如,对于使用OpenGL或其他渲染API的视频游戏),则浮点格式比double快得多(这是因为GPU制造商尝试增加图形内核的数量,因此他们尝试在每个内核中节省尽可能多的电路,因此针对float进行优化可以创建内部包含更多内核的GPU。
旧的GPU和某些移动设备只是不能接受double作为内部格式(用于3D渲染操作)

一般提示

在现代台式机处理器(可能还有大量的移动处理器)上,您基本上可以假设在堆栈上使用临时double变量可免费提供额外的精度(超精度而不会降低性能)。
请不要使用超出您所需精度的(您可能不知道您真正需要多少精度。)
有时,您只会受到值范围的限制(如果使用float,某些值将是无限的,但如果使用double,则可能是有限的值)
仅使用float或仅使用double可以极大地帮助编译器对指令进行SIMD化。

有关更多见解,请参阅PeterCordes的以下注释。

评论


只有在使用x87 FPU的x86上免费使用double temparies,而在SSE2上不可用。自动对具有双临时性的循环进行矢量化处理意味着将float分解为double,这需要额外的指令,并且每个矢量处理的元素数量要少一半。如果没有自动向量化,转换通常可以在加载或存储过程中即时发生,但是当您在表达式中混合使用浮点数和双精度数时,这意味着额外的指令。

– Peter Cordes
16年4月27日在19:17

在现代x86 CPU上,div和sqrt的float速度快于double速度,但其他速度相同(当然不包括SIMD向量宽度问题或内存带宽/缓存占用空间)。

– Peter Cordes
16-4-27在19:18



@PeterCordes感谢您提出一些意见。我不知道div和sqrt的差异

–CoffeDeveloper
16年4月28日在8:03

#6 楼

除了提到的其他原因之外,

如果您有测量数据,无论是压力,流量,电流,电压还是其他,通常都可以通过具有ADC的硬件来完成。
< br ADC通常具有10或12位,而14或16位则少见。但是,让我们坚持使用16位1-如果以满量程测量,则精度为1/65535。这意味着从65534/65535更改为65535/65535只是这一步-1/65535。大约是1.5E-05。浮子的精度约为1E-07,因此要好得多。这意味着使用float来存储这些数据不会造成任何损失。

如果对浮点数进行过多的计算,则在精度方面,与doubles相比,性能会稍差一些,但通常不会需要这种精度,因为您通常不关心测量的电压是2 V还是2.00002V。类似地,如果将此电压转换为压力,则不必关心是否为3 bar或3.00003 bar。 br />