7

I want to remove the sign of a Number in JavaScript. Here are the test cases that I already examined at jsperf

if(n < 0) n *= -1;

if(n < 0) n = -n;

n = Math.abs(n)

(n < 0) && (n *= -1)

(n < 0) && (n = -n)

n = Math.sqrt(n*n)

According to these tests: if(n < 0) n *= -1 seems to be a good solution.

Do you know of any better, save, and more efficient way to do that?

Edit 1: Added Nikhil's Math.sqrt case, but sqrt is usually quite slow in most systems.

Edit 2: Jan's proposal for bitwise ops may be faster in some cases but will also remove fractional digits, and thus will not work for me.

mikemaccana
  • 110,530
  • 99
  • 389
  • 494
Juve
  • 10,584
  • 14
  • 63
  • 90
  • 1
    Performance characteristics vary widely between browsers. On SeaMonkey, `Math.abs` clearly outperforms all the others. On Konqueror, bitwise (`if (n < 0) n = ~n+1`) shines [the `&&` variants are all bad there] and `Math.abs` stinks. All in all, `if (n < 0) n *= -1` and `if (n < 0) n = -n` seem to be the safe ones that don't stink too badly anywhere. One problem with bitwise operators is that they force the number into a 32-bit integer - if `n` falls outside that range, the bitwise way would produce garbage. – Daniel Fischer Jun 12 '13 at 13:00

6 Answers6

6

You could use Math.abs(). It returns the absolute value of the number

Davide Cavallini
  • 216
  • 4
  • 15
5

Since no better answer appeared I will summarize the findings in this answer myself.

  1. if(n < 0) n *= -1 Is currently the best choice. It performs reasonably well on most platforms and is very readable. It also preserves the decimal fractions.
  2. Other variants, such as n = Math.abs(n), might be faster on other platforms. But the gain is usually only a few percentages. You may consider detecting the browser/platform upfront and building platform-depended code that uses one or the other variant. This can give you the best performance on each platform but introduces a lot of overhead.
  3. Be careful when considering bitwise operators, they might be faster on some platforms but can change the semantics of your program (removing decimal fractions).
Juve
  • 10,584
  • 14
  • 63
  • 90
2

Bitwise operators are the fastest, see the results.

if(n < 0) n = ~n+1;
Jan Turoň
  • 31,451
  • 23
  • 125
  • 169
  • 1
    May I ask why do you need this in javascript? Javascript is not supposed to be the fastest language. Why not use C or Assembly? – Jan Turoň Jun 12 '13 at 11:26
  • I am implementing a small proof-of-concept game engine in CoffeeScript and need this sign removal for some internal math. Your answer looks promising (though I'd still stick with the if-then *= -1) which seems to be a better option for good avg. performance across browsers and esp. for readability. If you explain what your code does in detail, and how is provides correct results (remove sign and preserve value) I might accept it as answer. Details are always good, esp. for all the other readers. Not everybody knows bitwise ops well, esp. in the Javascript community. – Juve Jun 12 '13 at 18:53
  • Sorry, I just tested some values and your solution also converts the JS floats to "ints" (Yes I know that JS only uses floats). That is not what I wanted. I need to remove the sign from non-fixed numbers too. :( – Juve Jun 12 '13 at 19:00
0

Here is another way:

n * (n>>31|!!n) (not necessarily the fastest on all browsers, just another way)

That will always give a positive number. Basically >> shifts all the bits and keeps the sign. That is then bitwise OR'd with 0 or 1 (if positive instead), producing either -1, 0 , or 1. That means the sign gets multiplied by itself, making it always even.

Or even with a simple ternary operations:

n * (n < 0 ? -1 : 1)

or

n = n < 0 ? -n : n

The second one seems consistently fast across browsers, as is some others from the OP's original jsPerf: n > 0 || (n *= -1) and n < 0 && (n = -n), which are also consistently fast.

jsPerf: https://jsperf.com/remove-sign-from-a-number

James Wilkins
  • 6,836
  • 3
  • 48
  • 73
0

Not sure if this is an XY problem type situation, but zero-fill right-shifting by 0 gets rid of the sign bit. I can't think of a faster way.

1 >>> 0; // 1
-1 >>> 0; // 4294967295
  • 1
    Not only does it get rid of the sign bit, it also creates a different number for every negative number which is not what the OP wants -- they want merely the sign gone. (Also, `1 >>> 0` is 1 and not 100!) – Alexander Leithner Mar 29 '21 at 13:48
-1

You can also use n=Math.sqrt(n^n)

Nikhil
  • 143
  • 2
  • 7