-3

I'm trying to find a way to check if a floating point number is negative without branching.

float a = -0.5;
int getSignOfa= *(int*)&a >> 31; //type-pun to int and get signed bit;

Is this a safe way of checking the signed bit of a float?

Zachwuzhere
  • 329
  • 3
  • 12
  • 4
    safe? no, since there's no guarantee that `float` is the same size as `int`, and that also violates the strict aliasing rule – phuclv Nov 28 '18 at 03:23
  • 2
    Please pick one programming language. You've tagged 2. Solutions differ. – Antti Haapala -- Слава Україні Nov 28 '18 at 03:33
  • @phuclv assuming both float and int are 32 bit and the strict aliasing rule is disabled, will it work 100%? – Zachwuzhere Nov 28 '18 at 03:37
  • 2
    Be aware this kind of type casting can be extremely slow depending upon the target architecture. On powerpc this will take the floating point value in the register. Save it to memory on the stack. Read it back from memory to put it into a GPR register. Then shift and mask the GPR register. Or you could have had a single `int negative = a < 0.0f` which is two instructions. – fdk1342 Nov 28 '18 at 03:38
  • 1
    No, it won't always work. Depending upon compiler and optimization levels the compiler can see that this operation in undefined by the C language and set getSignOfa to anything it wants. See http://blog.qt.io/blog/2011/06/10/type-punning-and-strict-aliasing/ – fdk1342 Nov 28 '18 at 03:47
  • 1
    @Zachwuzhere Most of what you are writing is implementation defined. That's the point of writing in a language other than assembly. The compiler will do what it thinks is best for your processor architecture. Use something in the language like `signbit` if you want the best performance for this because even inline assembly can cause the complier to do extra register rearranging to accommodate it. – contrapants Nov 28 '18 at 03:49
  • 1
    Whats wrong with what eg. clang -O3 produces for `!(v < 0.f)` *~>* `xorps xmm1, xmm1 \ ucomiss xmm1, xmm0 \ setbe al` ? (gcc -03 *~>* `pxor xmm1, xmm1 \ comiss xmm1, xmm0 \ setbe al`) – Swordfish Nov 28 '18 at 04:03
  • @Swordfish Nothing, it's the best way of checking if it is negative. I tried pointing out that comparisons don't branch (that's what if statements and functions call do) but maybe didn't word it very well. – fdk1342 Nov 28 '18 at 04:10
  • 1
    Does `NaN` need to be handled? If you know that won't happen by the time this code is reached, a comparison makes much more sense than checking the sign bit. If `NaN` does need to be handled, you're probably going to have to branch to take care of it anyway. At that point, you're back at the first case where the comparison makes much more sense again. – contrapants Nov 28 '18 at 04:12
  • @Fred *best way of checking if it is negative.* – Ah, the op wanted negative ... well, add another bang ^^ – Swordfish Nov 28 '18 at 04:16
  • @Swordfish Not necessary `<` already returns zero or one. But `!!` is great for normalizing numbers to zero or one. – fdk1342 Nov 28 '18 at 04:19
  • @Free seems you didn't notice the ***^^*** – Swordfish Nov 28 '18 at 04:20
  • 1
    there are a lot of related and duplicate questions: [How to get the sign, mantissa and exponent of a floating point number](https://stackoverflow.com/q/15685181/995714), [How can I access the sign bit of a number in C++?](https://stackoverflow.com/q/3001653/995714), [Sign of a floating point number](https://stackoverflow.com/q/4235235/995714), [How can I access the sign bit of a number in C++?](https://stackoverflow.com/q/3001653/995714)... – phuclv Nov 28 '18 at 04:21
  • @Fred [example on how it's done on various architectures](https://godbolt.org/z/WVqaWg). I don't know about powerpc but it looks like the compiler indeed stores to memory and reload instead of moving from FPR to GPR like on many other architectures – phuclv Nov 28 '18 at 06:41
  • @phuclv Please change /O3 to /O2 for msvc and see \* *magic* \* ;) – Swordfish Nov 28 '18 at 06:55

2 Answers2

6

Since C99, you can use signbit(x) as defined in math.h to get the sign bit of a floating point number. It returns 0 if x is positive (sign bit not set) and nonzero if negative (sign bit is set).

contrapants
  • 775
  • 4
  • 16
  • Is the signbit function brachless? – Zachwuzhere Nov 28 '18 at 03:21
  • 1
    It's required to be implemented as a macro, but it is otherwise implementation-defined. – contrapants Nov 28 '18 at 03:23
  • 2
    [it's not a macro in C++](https://en.cppreference.com/w/cpp/numeric/math/signbit). @Zachwuzhere why you you care about that? Benchmark and if it's really slow then optimize it, otherwise it's premature optimization. The way from the standard is often the better solution – phuclv Nov 28 '18 at 03:26
  • 1
    I'm just going to add that `bool s = a < 0.0f` doesn't branch. It's a comparison that is probably just some sort of fsub instruction and then masks and shifts the floating point status register. Also what about NAN and Infinity? – fdk1342 Nov 28 '18 at 03:28
  • I'm creating a branchess ray-triangle intersection method for ray tracing and need it to be as fast as possible because there are millions of tests per second. – Zachwuzhere Nov 28 '18 at 03:34
  • 1
    @Fred that too is implementation-defined. – Antti Haapala -- Слава Україні Nov 28 '18 at 03:44
  • @Zachwuzhere that's better leave to the GPU, not CPU – phuclv Nov 28 '18 at 04:22
0

You may use copysign() functions available in math.h to get the sign of float number.

float sign = copysign(1, float_num);

Value of sign is going to be +1 or -1 depending upon the type of input.

Shravan40
  • 8,922
  • 6
  • 28
  • 48