I have a piece of Javascript code I'm trying to understand
// read big-endian (network byte order) 32-bit float
readFloat32 = function(data, offset) {
var b1 = data.charCodeAt(offset) & 0xFF,
b2 = data.charCodeAt(offset+1) & 0xFF,
b3 = data.charCodeAt(offset+2) & 0xFF,
b4 = data.charCodeAt(offset+3) & 0xFF;
var sign = 1 - (2*(b1 >> 7)); //<--- here it is and 2 lines below
var exp = (((b1 << 1) & 0xff) | (b2 >> 7)) - 127;
var sig = ((b2 & 0x7f) << 16) | (b3 << 8) | b4;
if (sig == 0 && exp == -127)
return 0.0;
return sign * (1 + sig * Math.pow(2, -23)) * Math.pow(2, exp);
}
what does ">>" mean? Is it a special type of boolean (like '<' or '>')
These are the shift right (with sign) and shift left operators.
Essentially, these operators are used to manipulate values at BIT-level.
They are typically used along with the the & (bitwise AND) and | (bitwise OR) operators and in association with masks values such as the 0x7F and similar immediate values found the question's snippet.
The snippet in question uses these operators to "parse" the three components of a 32 bits float value (sign, exponent and fraction).
For example, in the question's snippet:
1 - (2*(b1 >> 7)) produces the integer value 1 or -1 depending if the bit 7 (the 8th bit from the right) in the b1 variable is zero or one respectively.
This idiom can be explained as follow.
at the start, b1, expressed as bits is 0000000000000000abcdefgh
note how all the bits on the left are zeros, this comes from the
b1 = data.charCodeAt(offset) & 0xFF assignement a few lines above, which essentially zero-ed all the bits in b1 except for the rightmot 8 bits (0xFF mask).
a, b, c... thru h represent unknown boolean values either 0 or 1.
We are interested in testing the value of a.
b1 >> 7 shifts this value to the right by 7 bits, leaving
b1 as 00000000000000000000000a which, read as an integer will have value 1 or 0
this 1 or 0 integer value is then multiplied by 2
it is then either 2 or 0, respectively.
this value is then substracted from 1, leaving either -1 or 1.
Although useful to illustrate the way the bit-operators work, the above idiom could be replaced by something which tests the bit 7 more directly and assigns the sign variable more explicitly. Furthermore this approach does not require the initial masking of the leftmost bits in b1:
var sign
if (b1 & 0x80) // test bit 7 (0x80 is [00000000]10000000)
sign = -1;
else
sign = 1;
These are bit operators. Have a look at this link: Bitwise Operators
You can read about the operators here: https://developer.mozilla.org/en/JavaScript/Reference/operators/bitwise_operators
They are bit shifts and also occur in languages other than JS.
Example: 5 >> 1 = 2
binary: 0101 shifting one position = 0010
It is an arithmetic shift
Right and Left and shift operators.
shift a by b bits to the left (padding with zeros)
a << b
shift a by b bits to the right (copying the sign bit)
a >> b
From http://ecma262-5.com/ELS5_HTML.htm
11.7 Bitwise Shift Operators
ShiftExpression :
AdditiveExpression
ShiftExpression << AdditiveExpression
ShiftExpression >> AdditiveExpression
ShiftExpression >>> AdditiveExpression
11.7.1 The Left Shift Operator ( << )
Performs a bitwise left shift operation on the left operand by the amount specified by the right operand.
The production ShiftExpression : ShiftExpression << AdditiveExpression is evaluated as follows:
Let lref be the result of evaluating ShiftExpression.
Let lval be GetValue(lref).
Let rref be the result of evaluating AdditiveExpression.
Let rval be GetValue(rref).
Let lnum be ToInt32(lval).
Let rnum be ToUint32(rval).
Let shiftCount be the result of masking out all but the least significant 5 bits of rnum, that is, compute rnum & 0x1F.
Return the result of left shifting lnum by shiftCount bits. The result is a signed 32-bit integer.
11.7.2 The Signed Right Shift Operator ( >> )
Performs a sign-filling bitwise right shift operation on the left operand by the amount specified by the right operand.
The production ShiftExpression : ShiftExpression >> AdditiveExpression is evaluated as follows:
Let lref be the result of evaluating ShiftExpression.
Let lval be GetValue(lref).
Let rref be the result of evaluating AdditiveExpression.
Let rval be GetValue(rref).
Let lnum be ToInt32(lval).
Let rnum be ToUint32(rval).
Let shiftCount be the result of masking out all but the least significant 5 bits of rnum, that is, compute rnum & 0x1F.
Return the result of performing a sign-extending right shift of lnum by shiftCount bits. The most significant bit is propagated. The result is a signed 32-bit integer.
shift left and shift right operators. If you have a number it will shift its bits to left or right.
It's the bitshifting operator. See here for more details.
They are bitshift operators. Numbers in the computer are represented in binary. Shifting left is equivalent to multiplying by 2 and shifting right is equivalent to dividing by 2.
For example, the number 8 is 1000 in binary. Shift left << by 3 would yield 1000000 which is 64. Shift right by 2 would yield 10 which is 2.
Related
I understand what is Zero-fill right shift and results it yields make perfect sense when second operand is non-zero:
-7 >>> 1
2147483644
Compare with
-7 >> 1
-4
But when second operand is zero:
-7 >> 0
-7 // Looks right!
-7 >>> 0
4294967289 // What? Why?
If I'm shifting zero bits, doesn't it mean I'm not shifting at all? If that's the case, shouldn't it give me back the original number? I would expect -7 >>> 0 === -7
And also
-7 >>> 32
4294967289
Again, by definition, I would expect -7 >>> n === 0 where n >= 32 because all digits become zeros!
Found the internal workings of it in specs.
x >>> 0 will do ToUint32(x)
And
7.1.6 ToUint32 ( argument )
The abstract operation ToUint32 converts argument to one of 232
integer values in the range 0 through 232−1, inclusive. This abstract
operation functions as follows: Let number be ToNumber(argument).
ReturnIfAbrupt(number). If number is NaN, +0, −0, +∞, or −∞, return
+0. Let int be the mathematical value that is the same sign as number and whose magnitude is floor(abs(number)). Let int32bit be int modulo
232. Return int32bit.
Note Let int32bit be int modulo, and
The notation “x modulo y” (y must be finite and nonzero) computes a
value k of the same sign as y (or zero) such that abs(k) < abs(y) and
x−k = q × y for some integer q.
So by above convention, -7 mod 2^32 === 2^32 - 7 === 4294967289
I recently came across a strange piece of code that uses the >>>= operator (I'll show it later in the question).
The >>> is the unsigned right bit shift operator, as mentioned in What is the JavaScript >>> operator and how do you use it?
The mozilla documentation describes the operator as...
a >>> b shifts a in binary representation b (< 32) bits to the right, discarding bits shifted off, and shifting in zeroes from the left.
Given this knowledge, I have assumed that >>>= is the in-place unsigned right bit shift operator.
The strange piece of code
Remember that piece of code I mentioned at the start? Here it is...
(number) => {
number >>>= 0;
// Do stuff with number...
}
I'm very curious as to why someone would perform an in-place bit shift with 0.
What are the use-cases?
The attempt to find use-cases
In an attempt to answer my question, I wrote a quick script that would iterate through all unsigned 32-bit integers and compare the integer to its (unsigned right shifted by 0) counterpart.
"use strict";
const assertEqual = (a, b, message) => {
if (a !== b) {
throw message
}
}
const START = 0
const END = Math.pow(2, 32) - 1
for (let n = START; n < END; n++) {
let nShifted = n
nShifted >>>= 0
const message = n + " !== (" + n + " >>>= 0) (which is " + nShifted + ")"
assertEqual(n, nShifted, message)
}
console.log("done.")
As expected, the program finished with no exceptions, since bit-shifting by 0 will have no effect.
This, however, would throw an exception if any of the values were negative.
More experimenting
It appears that performing the shift truncates the result into a 32-bit integer, which isn't surprising.
It also appears that when shifting negative integers, the result is the two's complement, which makes sense because it's making the value unsigned.
For example...
x = -1
console.log(x.toString(2)) // '-1'
x >>>= 0
console.log(x.toString(2)) // '11111111111111111111111111111111'
// (Two's complement of -1)
As mentioned in the comments, using the operator on floating-point numbers will truncate the decimal section and result in an integer.
For example...
x = 2.6
x >>>= 0
console.log(x) // '2'
Summary
In-place right shifting by 0 an integer will truncate it to 32 bits and make it unsigned.
Are there any other use cases for this?
I want to do some bit operation in javascript on a variable. I have this numbers:
min: 153391689 (base 10) - 1111111111 (base 8)
max: 1073741823 (base 10) - 7777777777 (base 8)
Now I want to use this variable for storing 10 "vars" with options from 0 to 7.
For that, I need to get and set every octal digit (meaning 3 bits).
Unfortunately, I didn't made it, but I came with something:
var num = 153391689;
function set(val, loc) {
num |= val << (loc * 3);
}
function get(loc) {
return (num & 7 << loc * 3) / Math.pow(8, loc);
}
Thank you.
As mentioned by Amit in a comment, your set function doesn't clear the bits before setting the value, so if there is already a value at that location then the new value will be ORed with it.
You can clear the location by ANDing the number with the bitwise NOT of the bitmask for that position. Applying a bitwise NOT to the mask means that only bits that are not in the location you are interested in remain set.
function set(val, loc) {
num &= ~(7 << (loc * 3)); // clear bits
num |= val << (loc * 3); // set bits
}
Note that the brackets around the (loc * 3) are optional, because Javascript's order of operator precedence means that the multiplication will be done before the shift even without them.
Your get function looks like it will work, but you can simplify it. Instead of shifting the bitmask left, ANDing and then shifting right again (by doing a division), you can just shift right and then mask. This moves the bits you are interested in into the least significant 3 bits, and then masks them with the AND:
function get(loc) {
return (num >> (loc * 3)) & 7;
}
What is the meaning of this line of code
n = (n<<1) | ((d>=0.0004)?1:0);
Trying to understand code from here in function sigOff()
http://www.espruino.com/Remote+Control+Sockets
This snippet seems to use the bitwise OR (|) and left shift (<<) operators:
Bitwise OR: a | b;
Returns a one in each bit position for which the corresponding bits of either or both operands are ones.
Left shift: a << b;
Shifts a in binary representation b (< 32) bits to the left, shifting in zeros from the right.
The left shift by 1 (<< 1) basically doubles the value of n.
Then, the or (|) basically "adds" 1 to the result to make it uneven, if d >= 0.0004.
If d < 0.0004, the result from the left shift isn't changed.
So, for n == 3 and d == 0.0004, this happens:
n << 1 // 6
(d>=0.0004)?1:0 // 1
6 | 1 // 7
For n == 5 and d == 0.0002, this happens:
n << 1 // 10
(d>=0.0004)?1:0 // 0
10 | 0 // 10
Citing the ECMAScript spec Section 5.2:
The notation “x modulo y” (y must be finite and nonzero) computes a
value k of the same sign as y (or zero) such that abs(k) < abs(y) and
x−k = q × y for some integer q.
so if y is positive, the result k of 'x modulo y' is positive regardless of the sign of x.
and if my understanding is right, ToInt32(-1) equals ToInt32(1)?
The notation x modulo y is used internally within the spec to describe the result of certain operations. So yes, the result k of x modulo y is (by definition) of the same sign as y. It is not claimed that the % operator is equivalent to modulo.
If you're interested, the actual spec for % can be found under section 11.5.3. Interestingly, it makes no use of modulo.
Copy pasting from my previous answer here:
Take a % b
1. When both +ve, Modulo & Remainder are one and the same
2. When a is -ve, they are not the same
For example;
a = -10, b = 3
Remainder of -10 % 3 = -1
for Modulo, add a greater multiple of 3 to your 'a' and calculate the remainder.
-10 + 12 = 2
2 % 3 = 2 is your answer
The modulo operation is defined as the mathematical modulo operation:
Mathematical operations such as addition, subtraction, negation,
multiplication, division, and the mathematical functions defined later
in this clause should always be understood as computing exact
mathematical results on mathematical real numbers, which do not
include infinities and do not include a negative zero that is
distinguished from positive zero.
Your question:
ToInt32(-1) equals ToInt32(1)
Well, no:
Let posInt be sign(number) * floor(abs(number)).
posInt = sign(-1) * floor(abs(-1)) = -1;
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.
int32bit = posInt mod 4294967296 = -1 mod 4294967296 = 4294967295
(wolfram alpha link for mathematical result)
If int32bit is greater than or equal to 231, return int32bit − 232,
otherwise return int32bit.
Because 4294967295 >= 2147483648, we return 4294967295 - 4294967296, I.E. -1.
If we run the same steps for ToInt32(1), we get 1. So they don't have the same result.