Bitwise operation on octal number - javascript

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;
}

Related

How can I get integer in Math.pow(10, 10000000)

I always get infinity from:
let power = Math.pow(2, 10000000);
console.log(power); //Infinity
So, can I get integer from this?
Maybe I don't understand this task https://www.codewars.com/kata/5511b2f550906349a70004e1/train/javascript? Who knows, show me how to decide that?
The link that you give asks for the last digit of the number. In order to find such a thing, it would be insane to compute an extremely large number (which might exceed the storage capacity of the known universe to write down (*)) just to find the final digit. Work mod 10.
Two observations:
1) n^e % 10 === d^e % 10 // d = last digit of n
2) If e = 10q+r then n^e % 10 === (n^10)^q * n^d %10
This allows us to write:
const lastDigit = function(str1, str2){
//in the following helper function d is an integer and exp a string
const lastDigitHelper = function(d,exp){
if(exp.length === 1){
let e = parseInt(exp);
return Math.pow(d,e) % 10;
} else {
let r = parseInt(exp.slice(-1));
let q = exp.slice(0,-1);
return lastDigitHelper(Math.pow(d,10) % 10,q) * Math.pow(d,r) % 10;
}
}
let d = parseInt(str1.slice(-1));
return lastDigitHelper(d,str2);
}
This passes all of the tests, but isn't as efficient as it could be. The recursive helper function could be replaced by a loop.
(*) For fun: one of the test cases was to compute the last digit of
1606938044258990275541962092341162602522202993782792835301376 ^ 2037035976334486086268445688409378161051468393665936250636140449354381299763336706183397376
If written in base 2, this number would be approximately 4.07 x 10^92 bits long. Since there are fewer than that many atoms in the universe, the number is much too large to store, not to mention too time consuming to compute.
Javascript has a maximum safe integer:
Number.MAX_SAFE_INTEGER
9007199254740991
safe = the ability to represent integers exactly and to correctly compare them
In your case, the number is greater:
Math.pow(2, 10000000) >= Number.MAX_SAFE_INTEGER
true
Or not smaller:
Math.pow(2, 10000000) <= Number.MAX_SAFE_INTEGER
false
You can use an arbitrary size integer library like big-integer to work with larger integers

How to add bits in JavaScript

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.

What use-cases exist for using >>>= operator with 0? (Unsigned Right Bit Shift)

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?

How do I parse a two's complement string to a number

I have binary form for -3 in two's complement form - 11111111111111111111111111111101, and use it with parseInt function:
parseInt('11111111111111111111111111111101', 2)
But it returns 4294967293, which is the integer that results if 11111111111111111111111111111101 is parsed as unsigned int. How can I parse integer as a signed one?
~~parseInt('11111111111111111111111111111101',2)// == -3
is what you are looking for.
Related answer ~~ vs-parseint
var x = ~~y; is a 'trick' (similar to var x = y << 0;) that (ab)uses the unary bitwise NOT operator to force the result to be in the range of a signed 32-bit integer, discarding any non-integer portion.
i had the same problem, you can use the following:
function parseInt2complement(bitstring,bitcount)
{
value = parseInt(bitstring, 2);
if ((value & (1<<(bitcount-1))) > 0) {
value = value - (1<<(bitcount));
}
return value;
}
console.log(parseInt2complement('111111111111111111111111111101', 30))
console.log(parseInt2complement('1111111111111111111111111111101', 31))
For 32-bit numbers, it's enough to cast it to a 32-bit integer (no need for parseInt here), which can be done by applying any bitwise operation to it (and indicating that it's in binary by prefixing with 0b).
function parse(num){
return ('0b'+num) | 0
}
console.log(parse('11111111111111111111111111111101'))
For a non-32-bit number, however, you'll need some tricks:
function parse(num, length = num.length){
if(num[num.length-length] !== '1')
return +('0b'+num)
let inverse = ''
for(const digit of num.slice(-length))
inverse += +!+digit
return -('0b' + inverse) - 1
}
console.log(parse('1101', 4)) //-3
console.log(parse('1111111111111101', 16)) //-3
console.log(parse('1111111111111111111111111111111111111111111111111111111111111101', 64)) //-3
console.log(parse('1111111111111111111111111111111111111111111111111111111111111101')) //-3, bit length inferred from the length of the string

Javascript twos complement

The following python code seems to work very well to het the twos complement of a number:
def twos_comp(self, val, bits):
if (val & (1 << (bits - 1))) != 0:
val -= 1 << bits
return val
It is used as num = self.twos_comp(int(binStr, 2), len(binStr))
where binStr is a string that contains an arbitrary length binary number.
I need to do the exact same thing in javascript (for node.js). I've been fighting it all day and am about to resign from the human race. Clearly binary / bitwise math is not my strong suit.
Could someone please assist so I can go on to more productive time wasting :-)
function toTwosComplement(integer, numberBytes, dontCheckRange) {
// #integer - > the integer to convert
// #numberBytes -> the number of bytes representing the number (defaults to 1 if not specified)
var numberBits = (numberBytes || 1) * 8;
// make sure its in range given the number of bits
if (!dontCheckRange && (integer < (-(1 << (numberBits - 1))) || integer > ((1 << (numberBits - 1)) - 1)))
throw "Integer out of range given " + numberBytes + " byte(s) to represent.";
// if positive, return the positive value
if (integer >= 0)
return integer;
// if negative, convert to twos complement representation
return ~(((-integer) - 1) | ~((1 << numberBits) - 1));
}

Categories