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
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.
This code is undefined since it violates the strict aliasing rule.
What is the strict aliasing rule?
To do this well defined you will have to rely on the compiler optimizing it for you.
If you want portable way, just multiply by -1
and let compiler optimise it.