浮点转换和性能

Posted

技术标签:

【中文标题】浮点转换和性能【英文标题】:floating point conversions and performance 【发布时间】:2012-10-16 18:00:26 【问题描述】:

我知道在浮点数和整数之间进行转换时可能会出现错误,但是性能如何(请忽略准确性问题)?

如果我对不同算术类型的操作数(即不同的浮点类型(例如 floatdouble)和浮点/整数类型组合 (例如floatint)?是否存在经验法则,例如保持所有操作数的类型相同?

P.S.:我问是因为我正在编写一个表达式模板库,并且想知道是否允许对包含不同算术类型值的向量进行二进制运算。

【问题讨论】:

是的,不同类型之间的转换是有成本的。如果我期中回来时没有其他人回答,我可能会给出深入的回答。 由于浮点运算在 base-2 算术方面并不重要,编译器通常会发出辅助函数(看看为什么需要 libgcc?),这会严重影响性能。 问题是,您的程序对不同类型的操作数进行 n 元运算。它根据例如促进论点。 C99 的 6.3.1.8 通常的算术转换,然后进行 n 元运算,通常使用相同类型的参数(有一些例外,但没有涉及浮点类型)。 @Pascal Cuoq:我知道这些隐式转换,这就是我询问性能的原因。导致它们可能会产生成本,即使一切都可以编译并且工作正常。 @user1095108:我知道的最糟糕的成本是在 CPU 中从积分寄存器转移到浮点寄存器。如果你来回讨论它,尤其是。但除非它处于非常紧密的循环中,否则瓶颈更有可能是 CPU RAM 传输。 【参考方案1】:

我怀疑这个问题的答案会因目标架构而异,因为转换可以(但可能不会)发生在硬件中。例如,考虑以下代码,它会导致 int 和 float 之间的一些相互转换:

int main (int argc, char** argv)

    int precoarced = 35;
    // precoarced gets forced to float
    float result = 0.5 + precoarced;

    // and now we force it back to int
    return (int)result;

    // I wonder what the disassembly looks like in different environments?

当我尝试使用 g++(我在 Ubuntu,x86 上)使用默认设置编译它并使用 gdb 进行反汇编时:

   0x00000000004004b4 <+0>: push   %rbp
   0x00000000004004b5 <+1>: mov    %rsp,%rbp
   0x00000000004004b8 <+4>: mov    %edi,-0x14(%rbp)
   0x00000000004004bb <+7>: mov    %rsi,-0x20(%rbp)
   0x00000000004004bf <+11>:    movl   $0x23,-0x8(%rbp)
   0x00000000004004c6 <+18>:    cvtsi2sdl -0x8(%rbp),%xmm0
   0x00000000004004cb <+23>:    movsd  0x10d(%rip),%xmm1        # 0x4005e0
   0x00000000004004d3 <+31>:    addsd  %xmm1,%xmm0
   0x00000000004004d7 <+35>:    unpcklpd %xmm0,%xmm0
   0x00000000004004db <+39>:    cvtpd2ps %xmm0,%xmm0
   0x00000000004004df <+43>:    movss  %xmm0,-0x4(%rbp)
   0x00000000004004e4 <+48>:    movss  -0x4(%rbp),%xmm0
   0x00000000004004e9 <+53>:    cvttss2si %xmm0,%eax
   0x00000000004004ed <+57>:    pop    %rbp
   0x00000000004004ee <+58>:    retq   

注意带有 cvt 前缀的助记符的说明。这些是转换说明。因此,在这种情况下,转换是在硬件中通过少量指令进行的。因此,根据这些指令花费多少周期,它可能相当快。但同样,不同的架构(或不同的编译器)可能会改变故事。

编辑:有趣的是,由于我不小心指定了 0.5 而不是 0.5f,因此这里有一个额外的转换。这就是 cvtpd2ps op 存在的原因。

编辑:x86 长期以来一直支持 FP(自 80 年代以来),因此针对 x86 的 C++ 编译器通常会使用硬件(除非编译器严重落后于时代)。感谢 Hot Licks 指出这一点。

【讨论】:

编译器本可以很聪明地在编译时完成转换,但它不是...... @user1095108 确实如此。不过,这并不让我感到惊讶。我是在默认设置,一个。将浮点数作为这样的文字并不是典型的“实际”用例。此外,编译器实现者可能害怕任何与浮点相关的优化,因为他们必须非常小心。例如,您可能认为加法的交换性 (A+B=B+A) 将是浮点加法优化的有效基础,但由于 fp 不精确,它不是;它会严重破坏某些 FP 算法的精度。 请注意,从最初的 8087 协处理器开始,转换指令就以一种或另一种形式存在。因此,几乎所有具有浮点硬件的系统都会在硬件中进行转换。 @Hot Licks 说得好;任何现代的 x86 机器,搭配一个甚至还不错的编译器,都应该使用硬件。我必须承认我很好奇图片在非 x86 架构上看起来如何,尤其是在嵌入式应用程序中?我猜如果架构完全支持 FP,它也会提供转换功能(或者是 pure FP 架构),但也许有一些例外? 我知道 IBM Power 架构嵌入了完整的硬件浮点,并且我几乎确定其中包括转换。【参考方案2】:

在大多数机器上,浮点和整数格式之间的转换相当快,这得益于浮点硬件的特性。

但是,如果仅出于文档目的,当然应该努力以“正确”格式表达文字。并且在文档中使用显式转换也没有什么坏处。

【讨论】:

【参考方案3】:

通常会有一些性能损失,尽管与其他因素相比可以忽略不计。这是由于整数和浮点寄存器之间的数据迁移以及其他可能的 ABI 问题。

此类问题的答案总是相同的。怀疑? 对其进行基准测试。性能在理论上很难预测。

【讨论】:

别忘了,我问过关于经验法则的问题。我知道替补规则。

以上是关于浮点转换和性能的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中将对象数组转换为浮点数组 [关闭]

避免浮点运算

32 位到 16 位浮点转换

转帖AMD Zen 3处理器IPC性能提升17% 浮点性能大涨50%

为性能计数器分配一个浮点值

Raspberry Pi 上的浮点性能(ARM 架构,BCM2835)