1

Everyone knows the abs() function to get the absolute value of variables. Is there a similar function or efficient way of setting it ignoring the sign?

Practical example: Force minimum value for motor speed control

if (abs(speed) < 50 && speed != 0)
{
    if (speed < 0)
        speed = -50;
    else
        speed = 50;
}

I am looking for a standardized function or a clever bit manipulation one-liner. Wrapping the above if into a function or macro is obvious.

phuclv
  • 37,963
  • 15
  • 156
  • 475
mystery
  • 143
  • 5
  • 1
    `speed = (1 - 2*(speed < 0))*50` will do the inner bit. The expression `speed < 0` evaluates to `1` if `speed < 0` and `0` otherwise. – Peter Apr 06 '18 at 11:00

4 Answers4

3

It's basically the signum function

speed = 50*sgn(speed);

There's a standard function for this

speed = copysign(50, speed);

however this isn't quite efficient for integer types.

The sgn() function can be implemented using various other ways that you can find here

speed = ((speed > 0) - (speed < 0))*50;
phuclv
  • 37,963
  • 15
  • 156
  • 475
  • More importantly, going via a floating-point type will lose precision from large enough integers. – Toby Speight Apr 10 '18 at 18:17
  • @TobySpeight a double-precision type can store exactly all integers up to 2^53, so it'll work well for an `int32_t` – phuclv Apr 11 '18 at 01:39
2

Combining with answers you can find around SO, for example Fast sign of integer in C:

speed=((speed > 0) - (speed < 0)) * theNewValue;

You basically just want to keep the sign, and multiply it by a new norm.

kabanus
  • 24,623
  • 6
  • 41
  • 74
2

You're looking for an integer equivalent of the standard copysign() function.

The simplest way to do that is simply to multiply the absolute value of the magnitude argument by the sign of the sign argument, using one of the standard methods to obtain that:

int setabs(int magnitude, int sign)
{
     return magnitude
        * ((magnitude > 0) - (magnitude < 0))
        * ((sign > 0) - (sign < 0));
}

Tests to demonstrate:

int main()
{
    return
        + (setabs(50, 1) != 50)
        + (setabs(50, 0) != 0)
        + (setabs(50, -1) != -50)
        + (setabs(-50, 1) != 50)
        + (setabs(-50, 0) != 0)
        + (setabs(-50, -1) != -50);
}

If multiplications are expensive for you, then we can use subtraction of two booleans to make a slightly cheaper version (passing the same set of tests):

int setabs(int magnitude, int sign)
{
    return magnitude
        * ((magnitude > 0 == sign >= 0) - (magnitude > 0 == sign <= 0));
}

Any bit-manipulation techniques will depend on which representation is used by your platform for negative integers (sign-magnitude, one's-complement, two's-complement, ...), and will require casting the arguments to unsigned types (or rely on undefined behaviour).

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
0

It depends on your platform. Since you haven't said what system you're targeting, I'm going to assume your integers use sign+magnitude representation. ;-)

int setabs(int sign, int magnitude)
{
    static const unsigned mask =- 0^0;
    assert(mask); // in case it's used on weird (two's complement) systems
    return (int)((unsigned)sign&mask | (unsigned)magnitude&~mask);
}

You can then write

speed = setabs(speed, 50);
Toby Speight
  • 27,591
  • 48
  • 66
  • 103