right shift >> turns value into zero javascript - javascript

Trying some bit manipulation in javascript.
Consider the following:
const n = 4393751543811;
console.log(n.toString(2)) // '111111111100000000000000000000000000000011'
console.log(n & 0b11) // last two bits equal 3
const m = n >> 2; // right shift 2
// The unexpected.
console.log(m.toString(2)) // '0'
The result is 0? The expected output I am looking for after the right shift is:
111111111100000000000000000000000000000011 // pre
001111111111000000000000000000000000000000 // post >>
How is this accomplished?

Javascript bitwise operators on numbers work "as if" on 32bit integers.
>> (sign-propagating right-shift for numbers) will first convert to a 32-bit integer. If you read linked spec, note specifically
Let int32bit be int modulo 232.
In other words, all bits above 32 will simply be ignored. For your number, this results in the following:
111111111100000000000000000000000000000011
┗removed━┛┗━━━━━━━━━━━━━━32bit━━━━━━━━━━━━━┛
If you want, you can use BigInt:
const n = 4393751543811n; // note the n-suffix
console.log(n.toString(2))
console.log(n & 0b11n) // for BigInt, all operands must be BigInt
const m = n >> 2n;
// The expected.
console.log(m.toString(2))
The spec for >> on BigInt uses BigInt::leftShift(x, -y), where it in turn states:
Semantics here should be equivalent to a bitwise shift, treating the BigInt as an infinite length string of binary two's complement digits.

Related

Javascript XOR returning incorrect value of 0 [duplicate]

I am performing following operation
let a = 596873718249029632;
a ^= 454825669;
console.log(a);
Output is 454825669 but the output should have been 596873718703855301. Where I am doing wrong? What I should do to get 596873718703855301 as output?
EDIT: I am using nodejs Bigint library , my node version is 8.12.0
var bigInt = require("big-integer");
let xor = bigInt(596873718249029632).xor(454825669);
console.log(xor)
Output is
{ [Number: 596873717794203900]
value: [ 4203941, 7371779, 5968 ],
sign: false,
isSmall: false }
It is wrong. it should have been 596873718703855301.
From MDN documentation about XOR:
The operands are converted to 32-bit integers and expressed by a series of bits (zeroes and ones). Numbers with more than 32 bits get their most significant bits discarded.
Since the 32 least significant bits of 596873718249029632 are all 0, then the value of a is effectively 0 ^ 454825669, which is 454825669.
To get the intended value of 596873718703855301, BigInts can be used, which allow you to perform operations outside of the range of the Number primitive, so now your code would become:
let a = 596873718249029632n;
a ^= 454825669n;
console.log(a.toString());
In response to your edit, when working with integers and Number, you need to ensure that your values do not exceed Number.MAX_SAFE_INTEGER (equal to 253 - 1, beyond that point the double precision floating point numbers loose sufficient precision to represent integers). The following snippet worked for me:
var big_int = require("big-integer");
let xor = bigInt("596873718249029632").xor("454825669");
console.log(xor.toString());

XOR output is wrong in Javascript

I am performing following operation
let a = 596873718249029632;
a ^= 454825669;
console.log(a);
Output is 454825669 but the output should have been 596873718703855301. Where I am doing wrong? What I should do to get 596873718703855301 as output?
EDIT: I am using nodejs Bigint library , my node version is 8.12.0
var bigInt = require("big-integer");
let xor = bigInt(596873718249029632).xor(454825669);
console.log(xor)
Output is
{ [Number: 596873717794203900]
value: [ 4203941, 7371779, 5968 ],
sign: false,
isSmall: false }
It is wrong. it should have been 596873718703855301.
From MDN documentation about XOR:
The operands are converted to 32-bit integers and expressed by a series of bits (zeroes and ones). Numbers with more than 32 bits get their most significant bits discarded.
Since the 32 least significant bits of 596873718249029632 are all 0, then the value of a is effectively 0 ^ 454825669, which is 454825669.
To get the intended value of 596873718703855301, BigInts can be used, which allow you to perform operations outside of the range of the Number primitive, so now your code would become:
let a = 596873718249029632n;
a ^= 454825669n;
console.log(a.toString());
In response to your edit, when working with integers and Number, you need to ensure that your values do not exceed Number.MAX_SAFE_INTEGER (equal to 253 - 1, beyond that point the double precision floating point numbers loose sufficient precision to represent integers). The following snippet worked for me:
var big_int = require("big-integer");
let xor = bigInt("596873718249029632").xor("454825669");
console.log(xor.toString());

How to apply bitwise right shift operator on binary?

How can I perform bitwise right shift on binary?
>> in JS applies to integers. So, 6 >> 1 (bitwise shift right, step 1) shows 3 as result (110 >> 1 = 011 – correct). It is nice, but... Is it possible to work with shift right operator with binary?
I need this: 110 >> 1 working correctly. This will show 55 as result and it is correct. 110 is 01101110. 01101110 >> 1 = 00110111. 00110111 is 55. Correct. But I want 011 as result! How I can do this in js?
This looks like string manipulation to me. How about:
function shr(x, s) {
return
new String('0', Math.min(s, x.length)) +
x.substr(0, Math.max(0, x.length - s));
}
>>> shr('110', 1)
'011'
Alternatively, you can use the usual bitwise operators and simply convert from a string representation beforehand (once), and convert back to a string representation afterwards (once).
Here's one way to do it:
(parseInt("110",2) >> 1).toString(2) // gives "11"
parseInt can take a radix as a parameter, so if you pass it 2 it will treat the string as binary. So you convert to a number, shift it and then use toString (which conveniently also will take a radix as a parameter) to convert back to a binary string.

Bitwise operations on strings in javascript

In javascript the following test of character to character binary operations prints 0 676 times:
var s = 'abcdefghijklmnopqrstuvwxyz';
var i, j;
for(i=0; i<s.length;i++){ for(j=0; j<s.length;j++){ console.log(s[i] | s[j]) }};
If js was using the actual binary representation of the strings I would expect some non-zero values here.
Similarly, testing binary operations on strings and integers, the following print 26 255s and 0s, respectively. (255 was chosen because it is 11111111 in binary).
var s = 'abcdefghijklmnopqrstuvwxyz';
var i; for(i=0; i<s.length;i++){ console.log(s[i] | 255) }
var i; for(i=0; i<s.length;i++){ console.log(s[i] & 255) }
What is javascript doing here? It seems like javascript is casting any string to false before binary operations.
Notes
If you try this in python, it throws an error:
>>> s = 'abcdefghijklmnopqrstuvwxyz'
>>> [c1 | c2 for c2 in s for c1 in s]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for |: 'str' and 'str'
But stuff like this seems to work in php.
In JavaScript, when a string is used with a binary operator it is first converted to a number. Relevant portions of the ECMAScript spec are shown below to explain how this works.
Bitwise operators:
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.
ToInt32:
The abstract operation ToInt32 converts its argument to one of 232 integer values in the range −231 through 231−1, inclusive. This abstract operation functions as follows:
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 232; that is, a finite integer value k of Number type with positive sign and less than 232 in magnitude such that the mathematical difference of posInt and k is mathematically an integer multiple of 232.
If int32bit is greater than or equal to 231, return int32bit − 232, otherwise return int32bit.
The internal ToNumber function will return NaN for any string that cannot be parsed as a number, and ToInt32(NaN) will give 0. So in your code example all of the bitwise operators with letters as the operands will evaluate to 0 | 0, which explains why only 0 is printed.
Note that something like '7' | '8' will evaluate to 7 | 8 because in this case the strings used as the operands can be successfully convered to a number.
As for why the behavior in Python is different, there isn't really any implicit type conversion in Python so an error is expected for any type that doesn't implement the binary operators (by using __or__, __and__, etc.), and strings do not implement those binary operators.
Perl does something completely different, bitwise operators are implemented for strings and it will essentially perform the bitwise operator for the corresponding bytes from each string.
If you want to use JavaScript and get the same result as Perl, you will need to first convert the characters to their code points using str.charCodeAt, perform the bitwise operator on the resulting integers, and then use String.fromCodePoint to convert the resulting numeric values into characters.
I'd be surprised if JavaScript worked at all with bitwise operations on non-numerical strings and produced anything meaningful. I'd imagine that because any bitwise operator in JavaScript converts its operand into a 32 bit integer, that it would simply turn all non-numerical strings into 0.
I'd use...
"a".charCodeAt(0) & 0xFF
That produces 97, the ASCII code for "a", which is correct, given it's masked off with a byte with all bits set.
Try to remember that because things work nicely in other languages, it isn't always the case in JavaScript. We're talking about a language conceived and implemented in a very short amount of time.
JavaScript is using type coercion which allows it to attempt to parse the strings as numbers automatically when you try to perform a numeric operation on them. The parsed value is either 0 or more likely NaN. This obviously won't get you the information you're trying to get.
I think what you're looking for is charCodeAt which will allow you to get the numeric Unicode value for a character in a string and the possibly the complementary fromCodePoint which converts the numeric value back to a character.

Bitwise operations with big integers

I am implementing decoding of BER-compressed integers and recently I've found a weird JavaScript behavior related to bitwise operations with big integers.
E.g.:
var a = 17516032; // has 25 bits
alert(a << 7) // outputs -2052915200
alert(a * 128) // outputs 2242052096
alert(2242052096 >> 16) // outputs -31325
alert(2242052096 / 65536) // outputs 34211
While the first workaround (multiplication instead of left shift) is acceptable, the second isn't.
Why it happens? How to bear with it?
17516032 in binary is 00000001000010110100011000000000. Shifting to the left by 7 gives you 10000101101000110000000000000000. This is equal to -2052915200 in two's complement (which is how almost all computers represent negative numbers).
>> is a signed right shift. That means that the leftmost bit (which determines the sign of a number) will be shifted into the left side.
e.g.
1100 >> 2 == 1111
0111 >> 2 == 0001
If you want to do an unsigned shift (which ignores the sign bit), use >>> which will zero-fill the left end of the bitstring.
Bitwise operators work on 32 bit integers, while multiplication and division works on floating point numbers.
When you shift a number, it's converted from a floating point number to a 32 bit integer before the operations, and converted back to a floating point number after the operation. The number 2242052096 has the 32nd bit set, so it is a negative number when converted to and from a 32 bit integer.
The >> right shift operator doesn't change the sign of the value, i.e. the bits that are shifted in from the left have the same value as the sign bit. Use the >>> right shift operator to shift in zero bits instead.
Reference: MDN: Bitwise operators
(2242052096 / 65536) == (2242052096 >>> 16)
Note the different shift.
Javascript normally represents numbers as (double-precision) floating point.
Almost all bitwise operations convert to a signed 32-bit integer, do whatever they're going to do, then treat the result as a signed 32-bit integer when converting back.
The exception is >>> which treats the result as an unsigned 32-bit integer when converting back.
So:
right shifts can be made to work simply by using >>> instead of >> ;
a * 128 gives the expected answer because it's never converted to a signed 32-bit integer in the first place - it's just a floating-point multiplication;
a << 7 gives an unexpected answer because it's converted to a signed 32-bit integer, and then you shift a 1 into the sign bit, resulting in a negative signed 32-bit value.
There isn't a <<<, but if you want to write your left shift as a shift, you can use
(a << 7) >>> 0
to get the expected answer (the >>> 0 effectively casts the signed 32-bit value to an unsigned 32-bit value).

Categories

Resources