Bit-tweaking in Javascript - javascript

Just curious. I did a program in C, with quite an amount of bitwise operations for a variable which defines access controls for a page. I wanna be able to do the same in Javascript only. How can i accomplish this ordeal?
Any help in bit-tweaking in Javascript will help. Remember no costly functions allowed.

JavaScript has the usual assortment of bitwise operators, |, &, ~, etc.; details in the specification.
The following sections will be particularly useful:
Section 11.4.8: Bitwise NOT (~)
Section 11.7: Bitwise Shift Operators (<< and >>)
Section 11.10: Binary Bitwise Operators (| and &)
Note that JavaScript's numbers are all floating point (see Section 8.5, The Number Type, in the specification), but the bitwise operations are defined in terms of integers. So for instance, the definition of the bitwise NOT operator:
11.4.8 Bitwise NOT Operator ( ~ )
The production UnaryExpression : ~ UnaryExpression is evaluated as follows:
1. Let expr be the result of evaluating UnaryExpression.
2. Let oldValue be ToInt32(GetValue(expr)).
3. Return the result of applying bitwise complement to oldValue. The result is a signed 32-bit integer.
Any decent implementation will be able to handle these efficiently, avoiding unnecessary conversions from Number to internal integer and back.

JavaScript has bitwise operators like other languages. Bitwise operators are, by definition, efficient. You should be able to replicate all the bitwise operations performed in your C program in JS as well.
http://www.eecs.umich.edu/~bartlett/jsops.html

Related

I do not understand about bitwise operator in Javascript

I am student studying programming.
As far as I know, Javascript saves number as float.
However, bitwise operator in Javascript run as a type of number is integer.
For instance,
> 1 | 2 // -> 3
> 2 << 4 // -> 32
How is it possible?
I find official documentation(mdn web docs), but I can not find the reason.
The bitwise operators in JavaScript convert numbers to 32-bit integers before performing the operation. This means that even though JavaScript saves numbers as floats, the bitwise operators treat them as 32-bit integers. This is why you are able to use the bitwise operators on numbers and get integer results.
As #rviretural_001 mentioned, JavaScript does some automatic conversions by spec. For example, in addition to IEEE 754 doubles to 32 signed integers:
0 == '0' // true
String to Integer (Shift Right)
'4' >> 1 // 2
Converting to Integer (Bitwise OR)
'1.3' | 0 // 1
This last one was used in asm.js for 32 signed integers
just to contribute to the answers above note that the conversion of a floating-point number to an integer is done by removing the fractional part of the number.
For example, if you have the number 4.5 and you use a bitwise operator on it, JavaScript will convert it to the integer 4 before performing the operation.
This tutorial might help you to find out more https://www.programiz.com/javascript/bitwise-operators
Also note that performing bitwise operations on floating-point numbers can lead to unexpected results. This is due to the way floating-point numbers are represented in memory. So, it's recommended to avoid using bitwise operators on floating-point numbers in JavaScript.

What is this asm style "x | 0" some javascript programmers are now using?

I've seen some performance critical javascript code, like the one on this project that makes extensive use of bitwise OR operations with 0. Ex:
GameBoyAdvanceCPU.prototype.write8 = function (address, data) {
address = address | 0;
data = data | 0;
this.memory.memoryWrite8(address | 0, data | 0);
I know about the use case of flooring numbers with "|0", but that isn't the case here, as these are always int's. It looks a bit like asm.js, is this to tell the js engine that we are working with integers, allowing some optimizations? If so, which browsers will make those optimizations?
Any pointers to how this works would be appretiated.
According to JavaScript Performance for Madmen
Wrapping integer arithmetic expressions in ( ) | 0 allows the runtime to be sure that you're doing integer arithmetic instead of floating-point arithmetic. This allows it to avoid checking for overflow and produce faster code in many cases.
and according to the page, it's true for "most" Javascript runtimes, but doesn't say which.
As a second source, Writing Fast JavaScript For Games & Interactive Applications states
To tell JavaScript engine we want to store integer values [...] we could use bitwise or operator:
and a third source from Microsoft's Writing efficient JavaScript page:
[...] explicitly tell the JavaScript runtime to use integer arithmetic [...] use the bitwise or operator
Also, apart from in comments, none of the pages above mention asm.js, so I suspect such optimizations apply in code not explicitly marked as asm/in browsers that don't explicitly recognize it.
Referencing the Ecmascript 5 spec: 11.10 Binary Bitwise Operators, namely
The production A : A # B, where # is one of the bitwise operators in
the productions above (&; ^; |), is evaluated as follows:
Let lref be the result of evaluating A.
Let lval be GetValue(lref).
Let rref be the result of evaluating B.
Let rval be GetValue(rref).
Let lnum be ToInt32(lval).
Let rnum be ToInt32(rval).
Return the result of applying the bitwise operator# to lnum and rnum. The result is a signed 32 bit integer.
And noting that ToInt32() is defined as
Let number be the result of calling ToNumber on the input argument.
If number is NaN, +0, −0, +∞, or −∞, return +0.
Let posInt be sign(number) * floor(abs(number)).
Let int32bit be posInt modulo 2^32; that is, a finite integer value k of Number type with positive sign and less than 2^32 in magnitude such that the mathematical difference of posInt and k is mathematically an integer multiple of 2^32.
If int32bit is greater than or equal to 2^31, return int32bit − 2^32, otherwise return int32bit.
It then logically follows (which you can confirm in your own console) that for example
((Math.pow(2, 32)) + 2) | 0 === 2
(Math.pow(2, 31)) | 0 === -2147483648 === -(Math.pow(2, 31))
And so forth.
Shortly put, the operation turns the number to a 32-bit integer (which has its knacks, see the second example above and the ToInt32() definition for an explanation) and then does a logical or with zero which doesn't change the output beyond the first conversion.
Essentially it's a very cost-efficient way to turn a number into a 32-bit integer because 1) it relies on browser's built-in ToInt32(); and 2) ToInt32(0) short-circuits to 0 (see the spec above) and therefore adds practically no additional overhead.
What it actually does can be seen in this fiddle
It's probing the variable against integer type in this case and either "flooring" or set it to 0 if not an integer.
Thus, there's a tremendous differnece to a = a || 0 which would leave a value of 3.2 untouched.
| operator is bitwise OR. It's used to do a bit by bit OR operation on two integers.
The usage here is a shortcut very similar to logical OR || operator to provide default value, with the exception that the result is integer only (as opposed to string...etc)
address = address | 0;
means "if address is a number, let's use it; otherwise, set it to 0".

What is "MultiplicativeExpression" means?

I was reading the EcmaScript6 specifications and in the Arithemetic operator section ( http://www.ecma-international.org/ecma-262/5.1/#sec-11.6.1 ) its mentioned like this
AdditiveExpression :
MultiplicativeExpression
AdditiveExpression + MultiplicativeExpression
AdditiveExpression - MultiplicativeExpression
What does this mean ?
An expression of multiplication or division.
See Section 11.5
From MDN article on Expressions and operators:
An expression is any valid unit of code that resolves to a value.
So in this case a MultiplicativeExpression is any unit of code that results in multiplication. Most commonly it involves the * operator.
You can read the Annotated EcmaScript as it contains some helpful links on top of the spec.
It means that the ECMA specification is written in Martian. Or by Martians. Or for Martians. I've never been too sure, exactly.
Err, but more helpfully, section 11.6.1 explains how the "addition operator" (what we primitive humans usually call the plus sign or just "+" or "+/-") should treat the result of statements of addition, subtraction, multiplication, division, modulus division, and even string concatenation.
In the header you quote, the writers are calling attention to the various statement types they are trying to define, which is both the simple and more complex case of multiple statements that must be combined (as with the last two lines).
Later in the section it defines how 'hinting' should be handled, in what cases the script should treat variables as numbers instead of strings, etc.
It's just a really esoteric way to put it.

Flooring numbers in JavaScript: ~~n, n|0 or Math.floor(n)?

I've recently discovered some other ways to remove the fractional part of numeric values in JavaScript other than Math.floor(n), specifically the double bitwise NOT operator ~~n and performing a bitwise or with 0 n|0.
I'd like to know what are the difference between these approaches and what the different scenarios are where one method is recommended over another.
The operands of all bitwise operators are converted to signed 32-bit integers:
Math.floor(2147483648) // 2147483648
2147483648 | 0 // 2147483648
~~2147483648 // 2147483648
Math.floor(2147483649) // 2147483649
2147483649 | 0 // -2147483647
~~2147483649 // -2147483647
So use Math.floor();
Be clear to the next person looking at your code and use Math.floor().
The performance gain of 1%-40% isn't really worth it, so don't make your code confusing and hard to maintain.
(I entirely agree with josh's answer: favor clear maintainable code.)
Here is an explanation on the other bit-wise approaches:
The bit-wise operators work because they only operator on 32-bit (signed) integers but numbers in JavaScript are all IEEE-754 values. Thus, there is an internal conversion (truncation, not floor!) that happens to operands for bit-wise operators.
The applied bit-wise operation (e.g. n<<0, ~~n or n|0) then acts as an identity function which "does nothing" to the converted values: that is, all of these approaches rely on the same conversion applied to bit-wise operands.
Try n as a negative number or a value outside of [-231, 231-1]:
(-1.23|0) // -1
Math.floor(-1.23) // -2
var x = Math.pow(2, 40) + .5
x|0 // 0
Math.floor(x) // 1099511627776
Happy coding.

Why is JavaScript bitwise OR behaving strangely?

In JavaScript, it seems:
(4294958077 | 0) == -9219
Why is it not 4294958077 ?
It suggests that there's some sort of overflow kicking in (although as I understand it a JavaScript Number type's range is +/- 9007199254740992 so that's odd in itself.)
Even if it was an overflow, surely
(4294958077 | 0) == 4294958077
should evaluate as true - but it doesn't.
Help please
It has nothing to do with floating point type or overflows. It returns -9219
because the standard mandates it, as all binary bitwise operations have to be done using signed 32-bit integers (ECMA-262 §11.10).
The production A : A # B, where # is one of the bitwise operators in the productions above, is evaluated as follows:
Let lref be the result of evaluating A.
Let lval be GetValue(lref).
Let rref be the result of evaluating B.
Let rval be GetValue(rref).
Let lnum be ToInt32(lval).
Let rnum be ToInt32(rval).
Return the result of applying the bitwise operator # to lnum and rnum. The result is a signed 32 bit integer.
4294958077 converted to a signed 32-bit integer (using the algorithm in ECMA-262 §9.5) is -9219, and 0 is still 0, so the bitwise-or will return -9219.
All numbers in Javascript are 64bit floating point numbers. Bitwise operations on floats are an edge case, so internally those floats are temporarily converted to a 32bit int, then the bitwise operation is performed - hence your overflow.
JavaScript bitwise numbers are stored as signed 64-bit floats, i.e. you only have 32-bits to use for the integer, which you have exceeded, so it's gone weird by converting it to an integer as best it can and then doing the operation.
More information here (especially the 'beyond 32-bit' section) but no real solution, so unfortunately, you'll need to work around it.

Categories