Thanks to everyone in advance:
alert((~1).toString(2));
This outputs: -10
But in PHP/Java it outputs 11111111111111111111111111111110
Am I missing something? Why does Javascript add a "-" to the output?
I know Java uses two's complement to represent negative numbers, and 11111111111111111111111111111110 in binary, which is what ~1 gives, represents -2. Or, represented in binary with a negative sign, -10, which is what you got.
The way you calculate the negative of 10 (in base 2) using two's complement is that you first invert all of the bits, giving you:
11111111111111111111111111111101
then you add 1, giving you:
11111111111111111111111111111110
I guess the same is happening in Javascript.
You can use the shift operator >>> to convert the number to an unsigned integer before converting to binary:
(~1 >>> 0).toString(2) // "11111111111111111111111111111110"
Short answer:
A bitwise NOT (~1) performs a 1's complement conversion of the
decimal which gives us -2
The .toString() function basically takes the decimal without the sign 2, converts it to binary 10 and adds a - sign which gives us -10.
A more detailed answer:
It's in the function .toString(). When you output a number via .toString():
If the numObj is negative, the sign is preserved. This is the case
even if the radix is 2; the string returned is the positive binary
representation of the numObj preceded by a - sign, not the two's
complement of the numObj.
Taken from the developer.mozilla.org we got this formula that calculates the 1's complement of an integer, this is used when you perform a NOT (~) on a decimal:
Bitwise NOTing any number x yields -(x + 1). For example, ~5 yields
-6.
Maybe it's better explained with this table and an example:
+-------------------------+-----+-----+-----+-----+-----+-----+------+
| Base 10 Integer | -3 | -2 | -1 | 0 | 1 | 2 | 3 |
+-------------------------+-----+-----+-----+-----+-----+-----+------+
| Base 10 1's Complement | 2 | 1 | 0 | -1 | -2 | -3 | -4 |
+-------------------------+-----+-----+-----+-----+-----+-----+------+
| Base 2 | | | | 0 | 1 | 10 | 11 |
+-------------------------+-----+-----+-----+-----+-----+-----+------+
| Result ~x.toString(2) | 10 | 1 | 0 | -1 | -10 | -11 | -100 |
+-------------------------+-----+-----+-----+-----+-----+-----+------+
Starting with Base 10 integer "2"
Base 10 integer "2" its 1's Complement is "-3". This is the same as performing a NOT (~)
.toString function take the unsigned value (= "3" in base 10 and = "11" in base 2)
.toString function adds a "-" symbol
.toString outputs "-11"
This assumes that you are working in 32 bits...
var valueToNot = parseInt("11110000", 2);
var notResult = 0xFFFFFFFF - valueToNot;
console.log(notResult.toString(2));
results in
11111111111111111111111100001111
Here's a solution to implement NOT in javascript. It ain't pretty but it works.
// Since ~ is the two's complement, then the one's complement is ~(num -1).
var num = 9;
num.toString(2); //returns 1001
~(num - 1).toString(2); //returns -1001
// WHAT the hell?? I guess the negative sign acts as a sign bit.
If you want to view the Binary String of a decimal after a NOT (bit Toggle), then use the following code.
// Programer: Larry Battle
// Purpose: Provide a bit toggle function for javascript.
var getStrCopy = function (str, copies) {
var newStr = str;
copies = (copies > 0) ? copies : 1;
while (--copies) {
newStr += str;
}
return newStr;
};
var convertDecToBase = function ( dec, base, length, padding ) {
padding = padding || '0' ;
var num = dec.toString( base );
length = length || num.length;
if (num.length !== length) {
if (num.length > length) {
throw new Error("convertDecToBase(): num(" + num + ") > length(" + length + ") too long.");
}
num = getStrCopy( padding, (length - num.length)) + num;
}
return num;
};
var formatBinaryStr = function( str ){
return str.replace( /\d{4}/g, '$& ' ).replace( /\s$/,'');
};
var toggleBits = function( dec, length, doFormat ){
length = length || 8;
var str = convertDecToBase( dec, 2, length || 8 );
var binaryStr = str.replace( /0/g, 'o' ).replace( /1/g, '0').replace( /o/g, '1' );
return ( doFormat ) ? formatBinaryStr( binaryStr ) : binaryStr ;
};
// The following requires Firebug or Google Chrome Dev Tools
clear();
console.log( toggleBits( 1 ) ); // returns "11111110"
console.log( toggleBits( 2 ) ); // returns "11111101"
console.log( toggleBits( 50, 16 ) );// returns "1111111111001101"
console.log( toggleBits( 15, 8, true ) ); // returns "1111 0000"
console.log( toggleBits( 520, 16, true ) ); //returns "1111 1101 1111 0111"
Related
In Bitwise operation, what does | 0x80 do? I know (& 0xFF) is convert value to 8 bit integer but how about (| 0x80) ?
I have the following code:
const buf = createHash('sha256').update('test').digest()
for (let i = 0; i < n; i++) {
const ubyte = buf.readUInt8(i)
const shifted = (ubyte >> 1) | mask
destBuf.writeUInt8(shifted, i)
mask = (ubyte & 1) * 0x80 // mask is 0 or 128
}
Can anyone explain that for me?
0x... means that what comes next is an hexadecimal number.
0x80 is the hexadecimal representation of the number 128. In binary, this equals 10000000.
The | character is the bitwise or operator. Suppose you have a 8-bit number:
a = xxxxxxxx
with x being either a 0 or a 1. Now, masking this number with 0x80 means:
xxxxxxxx | 10000000 = 1xxxxxxx
So it basically means you will have a 1 for your leftmost significant bit, while keeping all the other bits the same.
Now, in your code you use this mask in the line:
const shifted = (ubyte >> 1) | mask
What this does is takes the number ubyte:
ubyte = xxxxxxxy // x and y can be either 1 or 0
It shifts it right by onw digit:
ubyte >> 1 = zxxxxxxx // y gets lost, and z is a 0 if ubyte was unsigned.
Now it masks this number with your mask. When the mask is 128, the result is:
(ubyte >> 1) | 10000000 = 1xxxxxxx
So you will have a 1 as your most significant bit, and the other bits are unchanged.
It combines the bits of both participating numbers with the logical "or":
const b= 0x7;
function tst(a,b){
console.log(a.toString(2).padStart(8)+" first number: "+a)
console.log(b.toString(2).padStart(8)+" second number: "+b)
console.log((a | b).toString(2).padStart(8)+" bitwise overlay: "+(a|b))
console.log("----")
}
[0x80,0x6A,0x70,0x8f].forEach(a=>tst(a,b))
console.log(0.5 | 0); // 0
console.log(-1 | 0); // -1
console.log(1 | 0); // 1
Why does 0.5 | 0 return zero, but any integer (including negative) returns the input integer? What does the single pipe ("|") do?
This is a bitwise or.
Since bitwise operations only make sense on integers, 0.5 is truncated.
x | 0 is x, if x is an integer.
Bit comparison is so simple it's almost incomprehensible ;) Check out this "nybble"
8 4 2 1
-------
0 1 1 0 = 6 (4 + 2)
1 0 1 0 = 10 (8 + 2)
=======
1 1 1 0 = 14 (8 + 4 + 2)
Bitwise ORing 6 and 10 will give you 14:
alert(6 | 10); // should show 14
Terribly confusing!
A single pipe is a bit-wise OR.
Performs the OR operation on each pair
of bits. a OR b yields 1 if either a
or b is 1.
JavaScript truncates any non-integer numbers in bitwise operations, so its computed as 0|0, which is 0.
This example will help you.
var testPipe = function(input) {
console.log('input => ' + input);
console.log('single pipe | => ' + (input | 'fallback'));
console.log('double pipe || => ' + (input || 'fallback'));
console.log('-------------------------');
};
testPipe();
testPipe('something');
testPipe(50);
testPipe(0);
testPipe(-1);
testPipe(true);
testPipe(false);
This is a Bitwsie OR (|).
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.
So, in our case decimal number is converted to interger 0.5 to 0.
= 0.5 | 0
= 0 | 0
= 0
A bitwise OR (single pipe | ) produces a strange output for an undefined property (once it becomes NaN). As this post implies, ToInt32 is called internally on undefined, producing NaN. But why does NaN|largeNumber result in a large negative number if NaN | smallNumber results in a small number?
In action, (see console output):
http://jsfiddle.net/4ev1asw7/6/
Here's the code:
var foo = {};
foo.date = 1412146800000; //some epoch timestamp as an integer
console.log( 'result: ' + foo.notDefinedThingy | foo.date ); // outputs -897440384
console.log( 'to int 32: ' + parseInt(undefined) ); //outputs NaN
console.log( 'to int 32: ' + parseInt(undefined) | foo.date ); //outputs -897440384
console.log( 'Small number ' + parseInt(undefined) | 5 ); // outputs 5
Because the operands are converted to 32 bit signed integers, and your right operand has exceeded the boundary for a positive integer, so it does the normal thing, which is to wrap around to the lowest possible number for a 32 bit signed integer, and keep counting up. The NaN is just treated as 0.
var highest = Math.pow(2,32)/2-1; // 2147483647
var highest_plus_one = highest + 1; // 2147483648
var highest_plus_two = highest + 2; // 2147483649
var highest_plus_three = highest + 3; // 2147483650
var all = [
0 | highest, // will be the expected number
0 | highest_plus_one, // will be the lowest number in range
0 | highest_plus_two, // will be the lowest number plus 1
0 | highest_plus_three // will be the lowest number plus 2, ...etc
];
document.querySelector("pre").textContent = all.map(function(n, i) {
return "Highest + " + i + " = " + n;
}).join("\n");
<pre></pre>
this produces the same:
var a=new Int32Array(1);
a[0]=1412146800000;
console.log(a[0]); //-897440384
here i'm just forcing that same value you used into an Int32.
that value needs 41bits, so it gets truncated and uses only the least significant 32 bit, wich have "1" as the most significant bit, and so represents a negative number
(1412146800000).toString(2); //"10100100011001010100000100010010110000000"
"10100100011001010100000100010010110000000".substr("10100100011001010100000100010010110000000".length-32); //"11001010100000100010010110000000"
parseInt("11001010100000100010010110000000",2); //3397526912
a[0]=3397526912;
console.log(a[0]); //-897440384
console.log(0.5 | 0); // 0
console.log(-1 | 0); // -1
console.log(1 | 0); // 1
Why does 0.5 | 0 return zero, but any integer (including negative) returns the input integer? What does the single pipe ("|") do?
This is a bitwise or.
Since bitwise operations only make sense on integers, 0.5 is truncated.
x | 0 is x, if x is an integer.
Bit comparison is so simple it's almost incomprehensible ;) Check out this "nybble"
8 4 2 1
-------
0 1 1 0 = 6 (4 + 2)
1 0 1 0 = 10 (8 + 2)
=======
1 1 1 0 = 14 (8 + 4 + 2)
Bitwise ORing 6 and 10 will give you 14:
alert(6 | 10); // should show 14
Terribly confusing!
A single pipe is a bit-wise OR.
Performs the OR operation on each pair
of bits. a OR b yields 1 if either a
or b is 1.
JavaScript truncates any non-integer numbers in bitwise operations, so its computed as 0|0, which is 0.
This example will help you.
var testPipe = function(input) {
console.log('input => ' + input);
console.log('single pipe | => ' + (input | 'fallback'));
console.log('double pipe || => ' + (input || 'fallback'));
console.log('-------------------------');
};
testPipe();
testPipe('something');
testPipe(50);
testPipe(0);
testPipe(-1);
testPipe(true);
testPipe(false);
This is a Bitwsie OR (|).
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.
So, in our case decimal number is converted to interger 0.5 to 0.
= 0.5 | 0
= 0 | 0
= 0
my code is below, but sometimes it shows negative number, I think I have do it in wrong way. So I add max number to make it greater than zero, but binary operation is best.
var buff2hash = function(buff, part) {
var hash = buff[part * 4 + 3] << 24 |
buff[part * 4 + 2] << 16 |
buff[part * 4 + 1] << 8 |
buff[part * 4];
//return hash // this number will be negative sometimes
return hash < 0 ? hash + 4294967296 : hash;
};
var md5hashcode = exports.md5hashcode = function(key) {
return buff2hash(new Buffer(crypto.createHash('md5').update(key).digest()), 0);
};
The most significant bit of the hash variable is the sign. To "hack convert" hash into an unsigned 32-bit integer you do this:
return hash>>>0;
(Forget about all the hoopla that you have in your "return" line, just do the above.)