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

18,357

Solution 1

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.

Solution 2

a=-a

Solution 3

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.

Solution 4

If you want portable way, just multiply by -1 and let compiler optimise it.

Share:
18,357
hennes
Author by

hennes

var addictedTo = 'code';

Updated on June 05, 2022

Comments

  • hennes
    hennes almost 2 years

    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