I have this code. Please make me understand what does this code actually mean
for(var i = 0; i < input.length; i++)
{
x = input.charCodeAt(i);
output += hex_tab.charAt((x >>> 4) & 0x0F)
+ hex_tab.charAt( x & 0x0F);
}
What is 0x0F? And, >>> Mean?
>>> is the unsigned bitwise right-shift operator. 0x0F is a hexadecimal number which equals 15 in decimal. It represents the lower four bits and translates the the bit-pattern 0000 1111. & is a bitwise AND operation.
(x >>> 4) & 0x0F gives you the upper nibble of a byte. So if you have 6A, you basically end up with 06:
6A = ((0110 1010 >>> 4) & 0x0F) = (0000 0110 & 0x0F) = (0000 0110 & 0000 1111) = 0000 0110 = 06
x & 0x0F gives you the lower nibble of the byte. So if you have 6A, you end up with 0A.
6A = (0110 1010 & 0x0F) = (0110 1010 & 0000 1111) = 0000 1010 = 0A
From what I can tell, it looks like it is summing up the values of the individual nibbles of all characters in a string, perhaps to create a checksum of some sort.
0x0f is a hexadecimal representation of a byte. Specifically, the bit pattern 00001111
It's taking the value of the character, shifting it 4 places to the right (>>> 4, it's an unsigned shift) and then performing a bit-wise AND with the pattern above - eg ignoring the left-most 4 bits resulting in a number 0-15.
Then it adds that number to the original character's right-most 4 bits (the 2nd & 0x0F without a shift), another 0-15 number.
0x0F is a number in hexadecimal. And >>> is the bitwise right-shift operator.
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))
Say you have two integers 10 and 20. That is 00001010 and 00010100. I would then like to just basically concat these as strings, but have the result be a new integer.
00001010 + 00010100 == 0000101000010100
That final number is 2580.
However, I am looking for a way to do this without actually converting them to string. Looking for something more efficient that just does some bit twiddling on the integers themselves. I'm not too familiar with that, but I imagine it would be along the lines of:
var a = 00001010 // == 10
var b = 00010100 // == 20
var c = a << b // == 2580
Note, I would like for this to work with any sequences of bits. So even:
var a = 010101
var b = 01110
var c = a + b == 01010101110
You basic equation is:
c = b + (a << 8).
The trick here is that you need to always shift by 8. But since a and b do not always use all 8 bits in the byte, JavaScript will automatically omit any leading zeros. We need to recover the number of leading zeros (of b), or trailing zeros of a, and prepend them back before adding. This way, all the bits stay in their proper position. This requires an equation like this:
c = b + (a << s + r)
Where s is the highest set bit (going from right to left) in b, and r is the remaining number of bits such that s + r = 8.
Essentially, all you are doing is shifting the first operand a over by 8 bits, to effectively add trailing zeros to a or equally speaking, padding leading zeros to the second operand b. Then you add normally. This can be accomplishing using logarithms, and shifting, and bitwise OR operation to provide an O(1) solution for some arbitrary positive integers a and b where the number of bits in a and b do not exceed some positive integer n. In the case of a byte, n = 8.
// Bitwise log base 2 in O(1) time
function log2(n) {
// Check if n > 0
let bits = 0;
if (n > 0xffff) {
n >>= 16;
bits = 0x10;
}
if (n > 0xff) {
n >>= 8;
bits |= 0x8;
}
if (n > 0xf) {
n >>= 4;
bits |= 0x4;
}
if (n > 0x3) {
n >>= 2;
bits |= 0x2;
}
if (n > 0x1) {
bits |= 0x1;
}
return bits;
}
// Computes the max set bit
// counting from the right to left starting
// at 0. For 20 (10100) we get bit # 4.
function msb(n) {
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n = n + 1;
// We take the log here because
// n would otherwise be the largest
// magnitude of base 2. So, for 20,
// n+1 would be 16. Which, to
// find the number of bits to shift, we must
// take the log base 2
return log2(n >> 1);
}
// Operands
let a = 0b00001010 // 10
let b = 0b00010100 // 20
// Max number of bits in
// in binary number
let n = 8
// Max set bit is the 16 bit, which is in position
// 4. We will need to pad 4 more zeros
let s = msb(b)
// How many zeros to pad on the left
// 8 - 4 = 4
let r = Math.abs(n - s)
// Shift a over by the computed
// number of bits including padded zeros
let c = b + (a << s + r)
console.log(c)
Output:
2580
Notes:
This is NOT commutative.
Add error checking to log2() for negative numbers, and other edge cases.
References:
https://www.geeksforgeeks.org/find-significant-set-bit-number/
https://github.com/N02870941/java_data_structures/blob/master/src/main/java/util/misc/Mathematics.java
so the problem:
a is 10 (in binary 0000 1010)
b is 20 (in binary 0100 0100)
you want to get 2580 using bit shift somehow.
if you right shift a by 8 using a<<=8 (this is the same as multiplying a by 2^8) you get 1010 0000 0000 which is the same as 10*2^8 = 2560. since the lower bits of a are all 0's (when you use << it fills the new bits with 0) you can just add b on top of it 1010 0000 0000 + 0100 0100 gives you 1010 0001 0100.
so in 1 line of code, it's var result = a<<8 + b. Remember in programming languages, most of them have no explicit built-in types for "binary". But everything is binary in its nature. so int is a "binary", an object is "binary" ....etc. When you want to do some binary operations on some data you can just use the datatype you have as operands for binary operations.
this is a more general version of how to concatenate two numbers' binary representations using no string operations and data
/*
This function concate b to the end of a and put 0's in between them.
b will be treated starting with it's first 1 as its most significant bit
b needs to be bigger than 0, otherwise, Math.log2 will give -Infinity for 0 and NaN for negative b
padding is the number of 0's to add at the end of a
*/
function concate_bits(a, b, padding) {
//add the padding 0's to a
a <<= padding;
//this gets the largest power of 2
var power_of_2 = Math.floor(Math.log2(b));
var power_of_2_value;
while (power_of_2 >= 0) {
power_of_2_value = 2 ** power_of_2;
a <<= 1;
if (b >= power_of_2_value) {
a += 1;
b -= power_of_2_value;
}
power_of_2--;
}
return a;
}
//this will print 2580 as the result
let result = concate_bits(10, 20, 3);
console.log(result);
Note, I would like for this to work with any sequences of bits. So even:
var a = 010101
var b = 01110
var c = a + b == 01010101110
This isn't going to be possible unless you convert to a string or otherwise store the number of bits in each number. 10101 010101 0010101 etc are all the same number (21), and once this is converted to a number, there is no way to tell how many leading zeroes the number originally had.
This is a function where bytes comes from a string, and each letter's char code was grabbed to create an array of bytyes
function checksum(bytes) {
var a = 0;
var b = 0;
for (var i = 0; i < bytes.length; i++) {
a = (a + bytes[i]) % 0xff;
b = (b + a) % 0xff;
}
return (b << 8) | a;
}
I'm mostly confused at the role of % 0xff and b << 8. Could someone help me break this down?
a is equal to the sum of all the elements modulo 255
b is equal to the sum of all the values that a assumes modulo 255 (so 1 time the last element + 2 times the one before that ....)
The final value is a 16 bit number where the higher 8 bits are b and the lower 8 bits are a.
That is actually a Fletcher's checksum
https://en.wikipedia.org/wiki/Fletcher%27s_checksum
This function calculates a and b, and generates the checksum from it.
a is calculated as follows:
0+the value of the current char
a must be between 0 and 254, hence modulo 255 is applied
b is calculated as the cumulative value of a modulo 255
increase the value of b by a
b must be between 0 and 254, hence modulo 255 is applied
at the end the checksum is generated by concatenating a to b
take b's bits and move them 8 places to the left
set a to the right side of b
The result will have a length of 2 bytes (16 bits), where the first byte is b and the second a.
Example:
(c is the current char value)
c | a |b
----------------
8 |8 |8
13 |21 |29
5 |26 |55
0 |26 |81
180 |206 |287
100 |51 |83
cheksum = 51,83 = 0x3353 = 0011 0011 0101 0011
Why
9 >> 2 = 2
and
-9 >> 2 = -3
?
I mean, why not -2.
From the bitwise operators page on MDN -
"The operands of all bitwise operators are converted to signed 32-bit integers in big-endian order and in two's complement format. Big-endian order means that the most significant bit (the bit position with the greatest value) is the left-most bit if the 32 bits are arranged in a horizontal line. Two's complement format means that a number's negative counterpart (e.g. 5 vs. -5) is all the number's bits inverted (bitwise NOT of the number, a.k.a. one's complement of the number) plus one."
1001 (9) >> 2 = 10 (2)
2's compliment 9 to get -9 and do the same:
0111 (-9) >> 2 = 01
2's compliment the result and you get 11 or 3, so the answer is -3
-1 = 11111111
-2 = 11111110
-3 = 11111101
-4 = 11111100
..
-8 = 11111000
-9 = 11110111
thus
-9 >> 2 = -3
I've created this JSFiddle to illustrate my question.
It seems that 10 - 00 = 8 in this example.
The simple question: Why does #ha contain 8? Have I misunderstood something?
var a4 = new Date(2012,00,00,00,00,00,0010);
var b4 = new Date(2012,00,00,00,00,00,0000);
var c4 = a4-b4;
var d4 = document.getElementById("ha");
d4.innerHTML=c4;
When an integer literal starts with 0 it is interpreted as an octal literal, not a decimal literal. The literal 0010 has the same value as the literal 8 . Remove the leading zeroes.
using a leading 0 on a number is a signal to the processor that you're using an octal (base 8) number the same way that 0x indicates hex.
0010 - 0 == 010 == 8 in base ten
10 - 0 == 10 == 10 in base ten
0x10 - 0 == 0x10 == 16 in base ten