【问题标题】:Why are double preferred over float? [closed]为什么双重优先于浮动? [关闭]
【发布时间】:2014-05-14 03:29:16
【问题描述】:

在我所看到的大部分代码中,doublefloat 相比更受欢迎,即使在不需要高精度时也是如此。

既然在使用double类型(CPU/GPU/memory/bus/cache/...)的时候有performance penalties,那么这种double过度使用的原因是什么?

示例:在计算流体动力学中,我使用的所有软件都使用双精度数。在这种情况下,高精度是没有用的(由于数学模型中的近似值造成的误差),并且需要移动大量数据,可以使用浮点数将其减半。

今天的计算机功能强大这一事实毫无意义,因为它们被用来解决越来越复杂的问题。

【问题讨论】:

  • “即使不需要高精度” - 如果他们有floats,您可能会抱怨“即使不需要高性能”...
  • 因为性能是大多数代码路径最不关心的问题,而且额外的精度不会受到伤害(反之亦然?)
  • 根据架构,硬件(例如 x86)可能只实现 double 并通过转换为 double 并返回到 float 来模拟 float,从而使其更昂贵。
  • 这里是关于double和float转换的stackoverflow讨论stackoverflow.com/questions/16737615/…
  • @DavidRodríguez-dribeas 我想当你说double 已实现但float 未实现时,我想我明白了你所指的意思,但事实并非如此。旧的 FPU 指令适用于 80 位双扩展数字,既不是 float 也不是 double,但没关系:它可以加载和保存浮点数和双精度数而不会降低性能(也许具有讽刺意味的是,指令加载/保存 80 位浮点数 很慢)。在非古代 x86 系统上,float 和 double 都直接使用 SSE(2) 实现。

标签: c++ performance floating-point double


【解决方案1】:

其中:

  • 节省下来的钱几乎不值得(数字运算并不常见)。
  • 舍入误差会累积,因此最好从一开始就获得比所需更高的精度(专家可能知道无论如何它已经足够精确,并且可以精确地进行计算)。
  • 在内部使用 fpu 的常见浮点运算通常以双精度或更高精度运行。
  • C 和 C++ 可以从浮点数隐式转换为双精度数,反之则需要显式转换。
  • 可变参数和无原型函数总是得到双精度,而不是浮点。 (第二个仅在古 C 中,并被积极劝阻)
  • 您通常可以使用超出所需精度的操作进行操作,但很少使用更少的精度,因此库通常也支持更高的精度。

但归根结底,YMMV:为您自己和您的具体情况衡量、测试和决定。

顺便说一句:性能狂热者还有更多:使用 IEEE 半精度类型。几乎没有硬件或编译器支持它,但它再次将您的带宽需求减少了一半。

【讨论】:

  • “节省的钱几乎不值得” - 对于单个计算(例如将总和保存在单个变量中) - 当然。获取大量数据 - 不,您将带宽加倍。
  • “舍入误差累积” - 在许多情况下,与其他原因(例如数学模型)导致的误差相比,舍入误差可以忽略不计。
  • @presiuslitesnoflek - 是的,并非总是如此。但我会说在大多数情况下。
  • 是的,不膨胀缓存是使用较小尺寸的另一个原因。另一个是许多 SSE 指令具有双精度和浮点版本,而浮点版本在一条指令中操作两倍的数据。 (双倍带宽,双倍乐趣)
  • 我想补充一点,单浮点数的精度可能比人们天真的想的要多得多。在我使用 OpenGL 的经验中,我有好几次不得不从坐标中消除偏差,或者在时间周期函数上选择比我可能喜欢的更短的模数,这仅仅是因为我在 32 位浮点数中用完了精度,而这些浮点数是GPU。
【解决方案2】:

double 在某些方面是 C 语言中的“自然”浮点类型,它也会影响 C++。考虑一下:

  • 13.9 这样的朴素的普通浮点常量的类型为double。为了让它浮动,我们必须添加一个额外的后缀fF
  • C 中的 默认参数提升float 函数参数* 转换为 double:这发生在不存在参数声明时,例如当函数声明为可变参数(例如 printf)或不存在声明(旧式 C,在 C++ 中不允许)。
  • printf%f 转换说明符采用double 参数,而不是float。没有专门的打印方式float-s; float 参数默认提升为 double,因此匹配 %f

在现代硬件上,floatdouble 通常分别映射到 32 位和 64 位 IEEE 754 类型。硬件“本机”使用 64 位值:浮点寄存器是 64 位宽,并且操作是围绕更精确的类型构建的(或者内部可能比这更精确)。由于double 映射到该类型,因此它是“自然”浮点类型。

float 的精度对于任何严肃的数值工作都很差,缩小的范围也可能是一个问题。 IEEE 32 位类型只有 23 位尾数(8 位用于指数字段,1 位用于符号)。如果精度和范围的损失在给定的应用程序中不是问题,则 float 类型可用于在大型浮点值数组中保存存储。例如,音频中有时会使用 32 位浮点值来表示样本。

确实,使用 64 位类型比使用 32 位类型会使原始内存带宽增加一倍。但是,这只影响具有大量数据数组的程序,这些数据以显示较差局部性的模式访问。 64 位浮点类型的卓越精度胜过优化问题。根据“先做对,再做快”的原则,数值结果的质量比缩短运行时间更重要。


* 但是请注意,从float 表达式到double 没有一般的自动提升;这种类型的唯一提升是整体提升:charshort 和位域转到int

【讨论】:

  • 这句话有点问题:“硬件“本机”地使用 64 位值”。 SSE/AVX 寄存器为 128/256 位宽,可以打包浮点数和双精度数,因此这两种格式同样适用于硬件。
【解决方案3】:

在我看来,到目前为止的答案并没有真正理解正确的观点,所以这是我的破解。

简短的回答是 C++ 开发人员使用双精度浮点数:

  • 当他们不了解性能权衡时避免过早优化(“他们有更高的精度,为什么不呢?”是思考过程)
  • 习惯
  • 文化
  • 匹配库函数签名
  • 匹配易于编写的浮点字面量(您可以写成 0.0 而不是 0.0f)

对于单次计算来说,双精度可能和浮点一样快,因为大多数 FPU 的内部表示比 32 位浮点或 64 位双精度表示的范围更广。

但这只是图片的一小部分。如果您在缓存/内存带宽方面遇到瓶颈,那么当今的运营优化就没有任何意义。

这就是为什么一些寻求优化代码的开发人员应该考虑使用 32 位浮点数而不是 64 位双精度数的原因:

  • 它们适合一半的内存。这就像让你所有的缓存都是两倍大。 (大胜利!!!)
  • 如果您真的关心性能,您将使用 SSE 指令。对浮点值进行操作的 SSE 指令对 32 位和 64 位浮点表示具有不同的指令。 32 位版本可以在 128 位寄存器操作数中容纳 4 个值,但 64 位版本只能容纳 2 个值。在这种情况下,您可能会通过使用双倍浮点数来使您的 FLOPS 翻倍,因为每条指令操作的数据量是两倍。

总的来说,我遇到的大多数开发人员都对浮点数的真正工作原理缺乏了解。所以我对大多数开发人员盲目使用双精度并不感到惊讶。

【讨论】:

    【解决方案4】:

    这主要取决于硬件,但考虑到最常见的 CPU(基于 x86/x87)具有内部 FPU,以 80 位浮点精度(超过浮点数和双精度数)运行。

    如果您必须在内存中存储一​​些中间计算,则 double 是内部精度和外部空间的良好平均值。在单个值上,性能或多或少是相同的。它可能会受到大型数字管道上的内存带宽的影响(因为它们将具有双倍长度)。

    考虑浮点数的精度大约为 6 位十进制数字。在 N 立方复杂性问题(如矩阵求逆或变换)中,您在 muldiv 中损失了两个或三个以上,只剩下 3 个有意义的数字。在 1920 像素宽的显示器上,它们根本不够用(至少需要 5 个像素才能正确匹配一个像素)。

    这大致使 double 更可取。

    【讨论】:

    • 我同意,但有些问题并不要求精度,重要的是数据大小和传输速度(例如解决方案稳定的问题)。
    • “我同意……但是”(但否定同意)然后添加我也写过的内容的评论的目的是什么?
    • 假设有两类问题。 1) 一种精度至关重要,2) 一种计算时间很关键。你的回答适用于头等舱,在这方面我同意你的看法。第二类问题的一个例子可能是天气预报:如果计算某个时期所花费的时间比该时期本身长,那么预测是无用的(我会得到昨天的预测)。这就是“BUT”适用的情况。
    【解决方案5】:

    通常比较容易确定 double 是否足够,即使在需要大量数值分析工作来证明 float 足够的情况下也是如此。这样可以节省开发成本,并且如果分析不正确,则可能会产生错误结果。

    此外,使用 float 所带来的任何性能提升通常都比使用 double 小,这是因为大多数流行的处理器都以一种比 double 更宽的格式执行所有浮点运算。

    【讨论】:

      【解决方案6】:

      我认为更高的精度是唯一的原因。其实大部分人并没有想太多,他们只是使用双精度。

      我认为如果浮点精度对于特定任务来说足够好,那么没有理由使用双精度。

      【讨论】:

      • 我认为你是完全正确的。大多数开发人员似乎并没有过多地考虑(或理解)浮动表示的细节及其含义。这么多开发人员使用双精度的原因可能与您看到隐式 int/float float/int 转换无处不在的原因非常相似;缺乏理解多于必要。我认为答案是“这是文化”。然而,我认为这个答案中的想法可能会更加清晰,并提供更具体的细节作为选择/接受的可行答案。
      • IME,开发者倾向于盲目使用float,导致精度问题。
      猜你喜欢
      • 1970-01-01
      • 2022-11-30
      • 2012-12-29
      • 1970-01-01
      • 1970-01-01
      • 2011-12-13
      • 1970-01-01
      • 2014-11-12
      • 2014-09-02
      相关资源
      最近更新 更多