Fast and safe way to remove the sign of a singed number in JavaScript
Asked Answered
I

6

8

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.

Iliac answered 12/6, 2013 at 9:58 Comment(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.Enhance
S
7

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

Salema answered 22/6, 2020 at 12:50 Comment(0)
I
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).
Iliac answered 17/6, 2013 at 8:29 Comment(2)
I think that in nowadays the best way to remove the sign is using Math.absMetaxylem
All bitwise operators change operands to 32-bit integers for calculation then back for the result. Best to just avoid it in JS unless you intend to do bit-manipulation, or else unexpected results may occur. The number type is a 64-bit float.Gaiseric
S
2

Bitwise operators are the fastest, see the results.

if(n < 0) n = ~n+1;
Serpasil answered 12/6, 2013 at 11:25 Comment(3)
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?Tip
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.Iliac
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. :(Iliac
R
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

Revile answered 1/10, 2017 at 4:21 Comment(0)
O
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
Ornithology answered 29/3, 2021 at 11:0 Comment(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!)Darken
M
-2

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

Mcbrayer answered 12/6, 2013 at 10:3 Comment(2)
I guess you meant Math.sqrt(n*n)? I added that one to my cases, but it is much slower than the others.Iliac
It's a slow method for cpu. It needs to calculate the power and then sqrtSalema

© 2022 - 2024 — McMap. All rights reserved.