14

在 C 中翻转双精度(或浮点)符号的最快方法是什么?

我认为,直接访问符号位将是最快的方法,并发现以下内容:

double a = 5.0;
*(__int64*)&a |= 0x8000000000000000;
// a = -5.0

float b = 3.0;
*(int*)&b |= 0x80000000;
// b = -3.0

但是,以上不适用于负数:

double a = -5.0;
*(__int64*)&a |= 0x8000000000000000;
// a = -5.0
4

4 回答 4

44

如果你只是在前面加上一个否定运算符,任何体面的编译器都会实现这个位操作,即-a. 无论如何,你是在 OR-ing 位。你应该 XOR 它。这就是我测试过的编译器所做的(GCC、MSVC、CLang)。所以,帮自己一个忙,写-a

编辑:请注意,C 不强制执行任何特定的浮点格式,因此对非整数 C 变量的任何位操作最终都会导致错误行为。


编辑 2 由于评论:这是 GCC 为 x86_64 发出的否定代码

.globl neg
    .type   neg, @function
neg:
.LFB4:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    movq    %rsp, %rbp
    .cfi_offset 6, -16
    .cfi_def_cfa_register 6
    movss   %xmm0, -4(%rbp)
    movss   -4(%rbp), %xmm1
    movss   .LC0(%rip), %xmm0
    xorps   %xmm1, %xmm0  /* <----- Sign flip using XOR */
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE4:
    .size   neg, .-neg

需要注意的xorps是,XOR 是为浮点数设计的,照顾特殊条件。这是一个 SSE 指令。

于 2011-03-06T20:59:39.120 回答
34

a=-a

于 2011-03-06T21:00:53.113 回答
5

此代码未定义,因为它违反了严格的别名规则。 什么是严格的别名规则? 要做到这一点,您将不得不依赖编译器为您优化它。

于 2011-03-06T21:01:26.060 回答
4

如果您想要可移植的方式,只需乘以-1并让编译器对其进行优化。

于 2011-03-06T20:58:03.803 回答