浮点数还是双精度?

30

在进行算术运算(+-*/%)时,double和float哪个更快?考虑到内存原因,只使用float值是否值得?精度不是很重要。

如果我为使用的float数量越来越多而担心,可以随意称我为疯子。编辑1:这个问题之所以涉及到Android,是因为我认为内存很重要;如果是桌面开发,我甚至都不会问这个问题。


CPU在处理浮点数和双精度浮点数方面表现不佳,而整数则是理想的选择。您是否有一个计划使用浮点数或双精度浮点数的例子? - whirlwin
我在单位转换中使用它们(例如,从托到PSI或从PSI到帕斯卡)。虽然精度不是一个很大的问题,但如果我使用整数,那么准确性就会彻底消失。 - ahodder
1
@AedonEtLIRA,Whirlwin:他可能在谈论使用整数来实现自定义定点数学,这将允许您完全控制精度。 - Merlyn Morgan-Graham
@AedonEtLIRA:我问这个问题的原因是,“哪种数据类型更快”取决于编译器/JIT实现和架构。我认为唯一合理的方法(不赌博的情况下)是a)查看现有的框架或应用程序,模仿它们,或者b)创建两者的概念证明,尝试将其加载到与您实际最终使用相近的程度,并测量结果。 - Merlyn Morgan-Graham
2
你们有多少个这样的东西?10个可以节省40个字节。一万个它们可以节省40,000个字节。就性能而言,我不确定Android,但在x86上,我认为机器最喜欢使用双精度浮点数。 - Mike Dunlavey
显示剩余4条评论
8个回答

27

现在的CPU处理速度,在这两种类型的数据上应该大致相同。

"使用任何需要的精度以获得可接受的结果。"

这里在SO上已经有几次相关的提问了,这是其中的一篇

编辑:

就速度而言,在较新的硬件上,浮点数和双精度没有区别。

请查看developer.android.com上的这篇文章。


15

由于Dalvik从Froyo(API 8及更高版本)开始进行JIT(即时编译)优化,因此ADT v21提示建议使用Double而不是Float。

我曾经使用FloatMath.sin,但它建议我改用Math.sin,并在“解释问题”上下文菜单中提供以下内容。听起来像是关于double与float而不仅仅是三角函数相关的一般性消息。

"在旧版Android中,由于性能原因,建议使用android.util.FloatMath操作float。然而,在现代硬件上,double与float一样快(虽然它们占用更多内存),并且在最近的Android版本中,由于JIT对java.lang.Math的优化方式,FloatMath实际上比使用java.lang.Math更慢。因此,如果您只针对Froyo及以上版本,请使用Math而不是FloatMath。"

希望这可以帮助你。


6

我不建议使用快速操作,但我相信对于浮点数的操作会更快,因为它们是32位的,而双精度浮点数则为64位。


9
我写了一个用来过滤图形的代码。它使用了浮点数并花费了11秒的时间。当我改成使用双精度时,只需要5秒。这是在Galaxy Note上进行的测试。 - intrepidis
4
在大多数现代架构中,双精度浮点数通常至少和单精度浮点数一样快,甚至更快。 - phuclv
在现代架构中,SIMD指令使得浮点数比双精度浮点数更快。如果可以接受精度损失,整数也可以因为同样的原因而变得更快。 - Andrew

6

http://developer.android.com/training/articles/perf-tips.html#AvoidFloat

避免使用浮点数

在 Android 设备上,使用浮点数通常比整数慢约 2 倍。

在速度方面,现代硬件上的 float 和 double 没有区别。而在空间方面,double 大约是 float 的两倍大小。就像桌面机一样,如果空间不是问题,您应该优先选择 double 而不是 float。

除此之外,即使对于整数,一些处理器拥有乘法硬件但缺少除法硬件。在这种情况下,整数除法和取模操作将在软件中执行。如果您正在设计哈希表或进行大量数学运算,需要考虑这一点。


4

浮点数是32位或4字节。

双精度浮点数是64位或8字节。

所以,是的,根据Sun Java认证书,浮点数的大小只有一半。


5
如果大多数存储都在CPU寄存器中,并且寄存器足够大以容纳任何一种存储方式,并且使用相同数量的指令,则这意义不大。 - Merlyn Morgan-Graham
1
我确信这本书没有说它们的速度是两倍。 - user207421
3
@EJP和@Merlyn-非常抱歉。我已经更正了我的帖子。书中确实说它们的大小是原来的一半,所以在我看来这似乎意味着某种效率的提高。但显然我错了。 - dylan murphy

3
在现代硬件上,float 和 double 的速度没有区别。
非常廉价的设备似乎具有受限的FPU,其中float比double更快。我在一款被市场宣传为世界上最便宜的平板电脑之一的CMX设备上进行了测试:
- “float”测试代码需要4.7秒 - “double”相同代码需要6.6秒
这个问题已经被问了几次……
是的。因为答案因硬件类型而异。在台式电脑上,double的速度与float相同。在没有FPU的设备上(对 WLAN 路由器黑客很有趣),float 比 double 快2-5倍;在具有32位FPU的设备上(通常在工业和汽车应用中找到),甚至可以高达100倍。
请查看本文的最后一节…
文章的最后一节说,您必须在将要使用的硬件设备上进行时间测量才能确保100%的准确性。

1
安卓文档引用表明整数更适合快速操作。这一看似有些奇怪,但使用整数、浮点数或双精度浮点数的算法速度取决于多个层面:
  1. JIT或VM:它们将把数学运算转换为主机的本地指令集,这种转换对性能有很大影响。由于底层硬件在不同平台上可能差别很大,编写一个能够在所有情况下发出最佳代码的VM或JIT可能非常困难。最好还是使用JIT/VM推荐的快速类型(在本例中为整数),因为随着JIT和VM发出更有效的本地指令的能力越来越强,您的高级代码应该获得相关的性能提升而无需任何修改。

  2. 本地硬件(为什么第一级不完美):现今大多数处理器都有硬件浮点单元(支持浮点数和双精度浮点数)。如果存在这样的硬件单元,则浮点数/双精度浮点数可以比整数更快,除非还具有硬件整数支持。问题的复杂化在于,大多数CPU都有某种形式的SIMD(单指令多数据)支持,如果数据类型足够小,则允许操作向量化(例如,通过将两个浮点数放入每个寄存器中,在一个指令中添加4个浮点数,而不必为每个4倍精度浮点数使用一个完整寄存器)。这可以使使用更少位数的数据类型比双精度浮点数快得多,但牺牲了精度。

优化速度需要详细了解这两个层面及其相互作用。即使优化内存使用也可能很棘手,因为VM可以选择以更大的占用空间来表示您的数据,出于其他原因:浮点数可能在VM的代码中占用8个字节,尽管这种情况不太可能发生。所有这些几乎使优化成为可移植性的对立面。因此,在这里,最好使用VM推荐的“快速”数据类型,因为这应该在支持的设备上平均获得最佳性能。

即使在桌面上,这也不是一个糟糕的问题。是的,今天它们非常快,但如果您正在实现复杂的算法(例如快速傅里叶变换),即使进行小的优化也会对算法的运行时间产生巨大影响。无论如何,回答您的问题“哪个更快:浮点数还是双精度”,答案是“取决于” :)


0

我也对此感到好奇,于是写了一个小测试:

#include <iostream>
#include <chrono>

template<typename numType>
void test(void)  {
    std::cout<< "Size of variable: " << sizeof(numType) << std::endl;
    numType array[20000];

    auto t1 = std::chrono::high_resolution_clock::now();
    // fill array
    for( numType& number : array ) {
        number = 1.0014535;
    }

    auto t2 = std::chrono::high_resolution_clock::now();

    // multiply each number with itself 10.000 times
    for( numType& number : array ) {
        for( int i=0; i < 10000 ; i++ )  {
            number *= number;
        }
    }

    auto t3 = std::chrono::high_resolution_clock::now();

    auto filltime = t2 - t1;
    auto calctime = t3 - t2;

    std::cout<< "Fill time: " << filltime.count() << std::endl;
    std::cout<< "Calc time: " << calctime.count() << std::endl;
}

int main(int argc, char* argv[]) {
    test<float>();
    test<double>();
}

我在Ubuntu 12.04 x64下使用GCC编译并运行它,处理器为Intel i7 3930k。

以下是结果:

Size of variable: 4
Fill time: 69
Calc time: 694303

Size of variable: 8
Fill time: 76
Calc time: 693363

结果是可重复的。因此,对于双精度浮点数的内存分配需要稍微更长一些时间,但实际计算时间完全相同。


出于好奇,我还在Windows 7 x64下使用Visual Studio 2012以发布模式编译了它,在intel i7 920处理器上运行。

(时间单位不同,因此请勿将上述结果与以下结果进行比较:仅适用于内部比较)

Size of variable: 4
Fill time: 0
Calc time: 3200183

Size of variable: 8
Fill time: 0
Calc time: 3890223

结果可以重复。

似乎在Windows上,分配是瞬时的,也许因为Linux实际上只有在使用内存时才给你,而Windows则立即将所有内存交给你,需要更少的系统调用。或者可能赋值被优化掉了。

双倍精度乘法比浮点数慢21.5%。这个与之前的测试的差异可能是由于不同的处理器(至少我最好的猜测是这样)。


2
这个基准测试很有趣,但离题了。讨论是关于Android的Java。尽管事后看来,问题本身就被操纵了,因为手机上的硬件通常非常不同。 :-/ - ahodder

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