Bitwise operations on strings in javascript - 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.

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 operator in javascript different from XOR operator in python

I am trying to replicate some javascript code into python, and for some reason the XOR operator (^) in javascript gives me a different value than the XOR operator (^) in python. I have an example below. I know the values should be different because of Math.random(), but why is it like 4 significant digits longer?
Javascript:
console.log(Math.floor(2147483648 * Math.random()) ^ 1560268851466)
= 1596700165
Python:
import math
math.floor(2147483648 * random.random()) ^ 1560268851466
= 1559124407072
Your Python result is correct, given XOR's input bits. Your longer operand is on the order of 2^40, and so is your final result.
The Javascript result has been truncated to 32 bits, the shorter operand.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators:
Bitwise operators treat their operands as a sequence of 32 bits (zeroes and ones), rather than as decimal, hexadecimal, or octal numbers. For example, the decimal number nine has a binary representation of 1001. Bitwise operators perform their operations on such binary representations, but they return standard JavaScript numerical values.
However the particular code you are using can be "fixed" via XOR-ing the 32-bit part of your number, and simply adding the rest:
// 1560268851466 = 0x16B_4745490A
console.log( (Math.floor(2147483648 * Math.random()) ^ 0x4745490A) + 0x16B00000000);
(As 2147483648 is 0x8000000, the random part is "fine", it does not get truncated)

Unexpected results in JavaScript

Using the node.js console, I get the following unexpected results:
> 2 + "3"
"23"
> 2 * "3"
6
Why does the first example favor string concatenation and integer multiplication in the second example? I would not expect concatenation between different types, but rather an error to be thrown. If this is the behavior in JS, how can I predict the type of the final result?
In JavaScript the + operator serves as both addition and concatenation (joining two strings together) and will default to concatenation when one of the two values is a string.
Since you are using it between an integer and a string it will default to concatentation. If you ever need to force the addition operation you will need to make sure all of your values are numbers. You can do this with parseInt() and parseFloat() functions.
2 + parseInt("3"); // 5
The * operator is for multiplication only and as such it will automatically cast strings to numbers to perform the operation.
Given the above there's another trick you can use to force string numbers to actually become numbers which is multiplying them by 1 *1.
2 + "3"*1; // 5
According to ECMAScript 2015 Language Specification (Addition operator, Multiplicative operators), the evaluation of additive expression is (lprim is the left primitive (lval converted to primitive), rprim is the right one):
...
If Type(lprim) is String or Type(rprim) is String, then
Let lstr be ToString(lprim).
ReturnIfAbrupt(lstr).
Let rstr be ToString(rprim).
ReturnIfAbrupt(rstr).
Return the String that is the result of concatenating lstr and rstr.
Let lnum be ToNumber(lprim).
ReturnIfAbrupt(lnum).
Let rnum be ToNumber(rprim).
ReturnIfAbrupt(rnum).
Return the result of applying the addition operation to lnum and rnum.
The evaluation of multiplicative expression is:
...
Let lnum be ToNumber(leftValue).
ReturnIfAbrupt(lnum).
Let rnum be ToNumber(rightValue).
ReturnIfAbrupt(rnum).
Return the result of applying the MultiplicativeOperator
You can see that if it is an additive expression, it is first to check whether there is a String. If there is a String, string concatenation is executed. Otherwise, the values are converted to Number and an addition operation is executed.
If it is a multiplicative expression, it would always convert values to Number and deliver a multiplicative operation.

Why does string to number comparison work in Javascript

I am trying to compare a value coming from a HTML text field with integers. And it works as expected.
Condition is -
x >= 1 && x <= 999;
Where x is the value of text field. Condition returns true whenever value is between 1-999 (inclusive), else false.
Problem is, that the value coming from the text field is of string type and I'm comparing it with integer types. Is it okay to have this comparison like this or should I use parseInt() to convert x to integer ?
Because JavaScript defines >= and <= (and several other operators) in a way that allows them to coerce their operands to different types. It's just part of the definition of the operator.
In the case of <, >, <=, and >=, the gory details are laid out in §11.8.5 of the specification. The short version is: If both operands are strings (after having been coerced from objects, if necessary), it does a string comparison. Otherwise, it coerces the operands to numbers and does a numeric comparison.
Consequently, you get fun results, like that "90" > "100" (both are strings, it's a string comparison) but "90" < 100 (one of them is a number, it's a numeric comparison). :-)
Is it okay to have this comparison like this or should I use parseInt() to convert x to integer ?
That's a matter of opinion. Some people think it's totally fine to rely on the implicit coercion; others think it isn't. There are some objective arguments. For instance, suppose you relied on implicit conversion and it was fine because you had those numeric constants, but later you were comparing x to another value you got from an input field. Now you're comparing strings, but the code looks the same. But again, it's a matter of opinion and you should make your own choice.
If you do decide to explicitly convert to numbers first, parseInt may or may not be what you want, and it doesn't do the same thing as the implicit conversion. Here's a rundown of options:
parseInt(str[, radix]) - Converts as much of the beginning of the string as it can into a whole (integer) number, ignoring extra characters at the end. So parseInt("10x") is 10; the x is ignored. Supports an optional radix (number base) argument, so parseInt("15", 16) is 21 (15 in hex). If there's no radix, assumes decimal unless the string starts with 0x (or 0X), in which case it skips those and assumes hex. Does not look for the new 0b (binary) or 0o (new style octal) prefixes; both of those parse as 0. (Some browsers used to treat strings starting with 0 as octal; that behavior was never specified, and was [specifically disallowed][2] in the ES5 specification.) Returns NaN if no parseable digits are found.
Number.parseInt(str[, radix]) - Exactly the same function as parseInt above. (Literally, Number.parseInt === parseInt is true.)
parseFloat(str) - Like parseInt, but does floating-point numbers and only supports decimal. Again extra characters on the string are ignored, so parseFloat("10.5x") is 10.5 (the x is ignored). As only decimal is supported, parseFloat("0x15") is 0 (because parsing ends at the x). Returns NaN if no parseable digits are found.
Number.parseFloat(str) - Exactly the same function as parseFloat above.
Unary +, e.g. +str - (E.g., implicit conversion) Converts the entire string to a number using floating point and JavaScript's standard number notation (just digits and a decimal point = decimal; 0x prefix = hex; 0b = binary [ES2015+]; 0o prefix = octal [ES2015+]; some implementations extend it to treat a leading 0 as octal, but not in strict mode). +"10x" is NaN because the x is not ignored. +"10" is 10, +"10.5" is 10.5, +"0x15" is 21, +"0o10" is 8 [ES2015+], +"0b101" is 5 [ES2015+]. Has a gotcha: +"" is 0, not NaN as you might expect.
Number(str) - Exactly like implicit conversion (e.g., like the unary + above), but slower on some implementations. (Not that it's likely to matter.)
Bitwise OR with zero, e.g. str|0 - Implicit conversion, like +str, but then it also converts the number to a 32-bit integer (and converts NaN to 0 if the string cannot be converted to a valid number).
So if it's okay that extra bits on the string are ignored, parseInt or parseFloat are fine. parseInt is quite handy for specifying radix. Unary + is useful for ensuring the entire string is considered. Takes your choice. :-)
For what it's worth, I tend to use this function:
const parseNumber = (str) => str ? +str : NaN;
(Or a variant that trims whitespace.) Note how it handles the issue with +"" being 0.
And finally: If you're converting to number and want to know whether the result is NaN, you might be tempted to do if (convertedValue === NaN). But that won't work, because as Rick points out below, comparisons involving NaN are always false. Instead, it's if (isNaN(convertedValue)).
The MDN's docs on Comparision states that the operands are converted to a common type before comparing (with the operator you're using):
The more commonly used abstract comparison (e.g. ==) converts the operands to the same Type before making the comparison. For relational abstract comparisons (e.g., <=), the operands are first converted to primitives, then to the same type, before comparison.
You'd only need to apply parseInt() if you were using a strict comparision, that does not perform the auto casting before comparing.
You should use parseInt if the var is a string. Add = to compare datatype value:
parseInt(x) >== 1 && parseInt(x) <== 999;

How to find the 32-bit of a number

Can I ask how to find the 32-bit version of a number as I want to work around with numbers with the bitwise AND operator in JavaScript. It stated that the numbers perform bitwise operations in 32bit version.
Second question is it in JavaScript bitwise AND operator(&), the operation of numbers perform in 32-bit version, right? Then at the end does it convert it back to 64-bit version?
According to the ECMAScript specification, the return values from bitwise operations must be 32-bit integers. A relevant quote:
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.
Therefore to convert any number to a 32-bit integer, you can just perform a binary operation that would have no effect. For example, here I convert a float to an integer using a no-op binary or (| 0):
var x = 1.2, y = 1
x = x | 0
alert(x == y) # prints "true"

Categories

Resources