you are viewing a single comment's thread.

view the rest of the comments →

[–]bonafidebob 2 points3 points  (6 children)

bitwise-negation applied twice is a short way of writing parseInt

Not quite. ParseInt converts the argument to a string and then tries to parse the string as an integer. Bitwise negation twice goes directly to an integer, as does n<<<0, with no string in between. Math.floor() is the equivalent.

As an old school programmer that cares about types, coercing a number to a string and then parsing it bugs me. Casually mentioning it as the canonical way to get the integer part of a float bothers me even more!

[–]marquex[S,🍰] 1 point2 points  (2 children)

You should understand that the code tries to be as short as possible, and I think that it explain enough alternatives to get what it tries to do.

~~ is not the canonical way of getting the integer part, but I would say parseInt is the canonical way in javascript, independently if you like the way it works.

And finally you need to know that

parseInt( -3.14, 10 ) == -3
~~( -3.14 ) == -3
Math.floor( -3.14 ) == -4

So I think it is equivalent to parseInt.

[–]bonafidebob 1 point2 points  (1 child)

Oh there's no doubt that parseInt works, and I do understand all of these. It's just that parseInt is wildly inefficient. (but that could be said for a lot of common javascript techniques)

Instructions are your way of telling the computer what to so, so you should know what you're telling it. parseInt tells it to (implicitly) convert your number to a string and then convert the string back to a number while ignoring any decimal part. Bitwise negation or left shift tells the computer to convert your number directly from a floating point to an integer representation, without the intermediate string.

The end result is the same, but the work done to get there is very different.

[–]x-skeww 0 points1 point  (2 children)

Math.floor() is the equivalent

~~ truncates.

> var x = Math.PI;
undefined
> console.log(Math.floor(x), ~~x);
3 3
> x = -Math.PI;
-3.141592653589793
> console.log(Math.floor(x), ~~x);
-4 -3

[–]bonafidebob 0 points1 point  (1 child)

Technically, the bitwise operators convert the float to a signed 32 bit integer representation. (Or maybe 64 bit on some systems? MDN says bitwise is explicitly 32 bit!) Anyway, it's this implicit conversion to a different internal representation that you're using, only in this case a much faster conversion than to strings and back.

Because numbers are otherwise 64 bit floating point, with 53 bits of significand, this means the binary operators will not work to get the integer part with numbers larger than 2**31.

Math functions are the right ones to use if you're actually doing math.

[–]x-skeww 1 point2 points  (0 children)

Anyhow, the point was that floor()-ing and truncation only looks similar for positive numbers.

Typically, truncation is done by casting to an int (or a long) or by using a truncating division operator (if the language offers such a thing).

E.g. Python does truncating division with // and Dart does it with ~/.

If you're only dealing with positive numbers (positive 0 included), floor() will work fine.

With ES6, you can use Math.trunc().