Fastest way to flip the sign of a double / float in C

hennes picture hennes · Mar 6, 2011 · Viewed 16.5k times · Source

What is the fastest way to flip the sign of a double (or float) in C?

I thought, that accessing the sign bit directly would be the fastest way and found the following:

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

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

However, the above does not work for negative numbers:

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

Answer

datenwolf picture datenwolf · Mar 6, 2011

Any decent compiler will implement this bit manipulation if you just prepend a negation operator, i.e. -a. Anyway, you're OR-ing the bit. You should XOR it. This is what the compilers I tested it do anyway (GCC, MSVC, CLang). So just do yourself a favour and write -a

EDIT: Be aware that C doesn't enforce any specific floating point format, so any bit manipulations on non-integral C variables will eventually result in errornous behaviour.


EDIT 2 due to a comment: This is the negation code GCC emits for 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

It should be noted that xorps is XOR designed for floatin points, taking care of special conditions. It's a SSE instruction.