C/C++, unfortunately, does not have a sgn function in its standard library however this is defined in the Boost library.
1 2 | template <class T> inline int sign (const T& z); |
template <class T> inline int sign (const T& z);
Very Basic Sgn Implementation
According to the above sgn graph, we can write something like this (assuming type double, and we can move to generics using template in C++ later).
1 2 3 4 5 | int sgn(double v) { if (v < 0) return -1; if (v > 0) return 1; return 0; } |
int sgn(double v) { if (v < 0) return -1; if (v > 0) return 1; return 0; }
Sgn function using C/C++ Ternary Operator
The above can be converted into one line using C/C++ Ternary Operator.
1 2 3 | int sgn(double v) { return (v < 0) ? -1 : ((v > 0) ? 1 : 0); } |
int sgn(double v) { return (v < 0) ? -1 : ((v > 0) ? 1 : 0); }
As bool (FALSE) is evaluated to zero and TRUE is equal to one, the above can be simplied to :
1 2 3 | int sgn(double v) { return ( ( (v) < 0 ) ? -1 : ( (v) > 0 ) ) } |
int sgn(double v) { return ( ( (v) < 0 ) ? -1 : ( (v) > 0 ) ) }
Of course, if you are using C compiler (which does not support templates/generics), you may want to use the Macro instead.
1 | #define sgn(v) ( ( (v) < 0 ) ? -1 : ( (v) > 0 ) ) |
#define sgn(v) ( ( (v) < 0 ) ? -1 : ( (v) > 0 ) )
However in C++, we should prefer templates over macros.
Branchless Implementation
This simple task can be further improved using the following branchless expressions:
1 2 3 | int sgn(double v) { return (v > 0) - (v < 0); } |
int sgn(double v) { return (v > 0) - (v < 0); }
For example, if v=-1, above expression becomes (0) – 1 = -1, if v=0, above expression is evaluated to (0) – (0) = 0. The boolean (TRUE) is evaluated to 1 and boolean (FALSE) is evaluated to zero.
Make it Generics using Template
As the types can be of int, float, double etc, instead of overloading the Sgn functions for each type, we can make it generics using the template in C++.
1 2 3 4 5 | template <class T> inline int sgn(T v) { return (v > T(0)) - (v < T(0)); } |
template <class T> inline int sgn(T v) { return (v > T(0)) - (v < T(0)); }
The keyword class can be interchangable with typename in this case. The keyword inline makes it effient as the C++ compiler will inline this short code without actually calling it (which causes the stack frames creation and destruction).
The T(0) will be the zero value in that type, e.g. integer 0 or float 0.
Unit Test the Sgn function
We need to verify it before we have confidences to use it. So below are some good examples of the unit tests cases:
1 2 3 4 5 6 7 8 9 10 11 | assertEquals(0, sgn(0)); assertEquals(0, sgn(0.0)); assertEquals(0, sgn(0.0f)); assertEquals(1, sgn(1.3f)); assertEquals(1, sgn(110)); assertEquals(1, sgn(0.0001f)); assertEquals(1, sgn(0.5)); assertEquals(-1, sgn(-0.0003)); assertEquals(-1, sgn(-9.0f)); assertEquals(-1, sgn(-234234)); assertEquals(-1, sgn(-1.00003f)); |
assertEquals(0, sgn(0)); assertEquals(0, sgn(0.0)); assertEquals(0, sgn(0.0f)); assertEquals(1, sgn(1.3f)); assertEquals(1, sgn(110)); assertEquals(1, sgn(0.0001f)); assertEquals(1, sgn(0.5)); assertEquals(-1, sgn(-0.0003)); assertEquals(-1, sgn(-9.0f)); assertEquals(-1, sgn(-234234)); assertEquals(-1, sgn(-1.00003f));
–EOF (The Ultimate Computing & Technology Blog) —
Last Post: C/C++ Coding Exercise - Convert a Number to Hexadecimal?
Next Post: How to Disable Ads on the Specific Posts?