I want convert a integer form base 10 to base 42 in Javascript,
by default Javascript can do to base 36 not more.
How can I do to resolve this problem ?
To begin you need some sort of symbol system to represent digits. In base 10 we have 10: 0 - 9. In base 16 you have 16 0 - 9 and A – F. Binary, of course you only have 2: 0 and 1.
So for base 42 you'll need 42 types of digit. Since this just seems like an exercise maybe include upper and lower case digits (I'm sure there's a better scheme if you put your mind to it):
const symbols = "0 1 2 3 4 5 6 7 8 9 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f".split(" ")
So the numbers 0 - 41 will be 0 through f. 42 will start at 10 42**2 will be 100 etc.
To get the right-most digit, you can can take the number modulus the base. Then divide by the base (and take the floor) and do it again until your number is reduced to zero. With the above scheme here is counting to 100 base 42:
const symbols = "0 1 2 3 4 5 6 7 8 9 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f".split(" ")
function toBase(n, base){
if (n === 0 ) return symbols[n]
res = ""
while (n) {
res = symbols[n % base] + res
n = Math.floor(n / base)
}
return res
}
console.log(Array.from({length: 100}, (_, i) => toBase(i, 42)).join(", "))
Related
Every solution I've found uses the following object.
function converter(num) {
var romanKeys =
{M:1000,CM:900,D:500,CD:400,C:100,XC:90,L:50,XL:40,X:10,IX:9,V:5,IV:4,I:1}
When attempting the problem myself, I wasn't too sure which roman numerals were redundant when constructing the object. Procedurally, how do we arrive to this object? e.g How do I know that
"VI: 6" is unnecessary but "IV: 4" is?
When a symbol appears after a larger (or equal) symbol it is added
Example: VI = V + I = 5 + 1 = 6
Example: LXX = L + X + X = 50 + 10 + 10 = 70
But if the symbol appears before a larger symbol it is subtracted
Example: IV = V − I = 5 − 1 = 4
Example: IX = X − I = 10 − 1 = 9
I can be placed before V (5) and X (10) to make 4 and 9.
X can be placed before L (50) and C (100) to make 40 and 90.
C can be placed before D (500) and M (1000) to make 400 and 900.
When you are scanning a roman number you are looking from left to right at each symbol and if it appears before a larger symbol, you take them together, do the substraction and add it to the result, then move to the symbol after them. Otherwise you take a single symbol and add its value to the result and move to the next symbol.
For example for XIV:
1) result = 0
2) X < I => result += 10 (result = 10)
3) I < V => result += (5-1) (result = 14)
Note that if you are using that mapping, you only need the combinations where the second symbol is greater than the first one for which the substraction rule applies, as noted above (CM, CD, XC, XL, IX, IV).
Having something like XI in that mapping would give you a wrong result. For XIV you will have XI (11) + V (5) = 16, not X (10) + IV (4) = 14.
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.
I encountered a problem in the site CodeFights that I resolved with two loops. While looking at other answer I found one that resolved it with no loops and it left me with my mouth open. The coder applied Math.min/max , and while I do understand what the code does I don't understand why it works.
I've love to learn because heck, Math.max/min beats the bytes out of my loops for sure.
Given integers n, l and r, find the number of ways to represent n as a sum
of two integers A and B such that l ≤ A ≤ B ≤ r.
Example
For n = 6, l = 2 and r = 4, the output should be
countSumOfTwoRepresentations2(n, l, r) = 2.
There are just two ways to write 6 as A + B, where 2 ≤ A ≤ B ≤ 4: 6 = 2 + 4 and 6 = 3 + 3.
Input/Output
[time limit] 4000ms (js)
[input] integer n
A positive integer.
Constraints:
5 ≤ n ≤ 109.
[input] integer l
A positive integer.
Constraints:
1 ≤ l ≤ r.
[input] integer r
A positive integer.
Constraints:
l ≤ r ≤ 109,
r - l ≤ 106.
The coder's amazing answer:
function countSumOfTwoRepresentations2(n, l, r) {
return Math.max(Math.min(Math.floor(n / 2) - l, r - Math.ceil(n / 2)) + 1, 0);
}
My crap in comparison:
function countSumOfTwoRepresentations2(n, l, r) {
var representations = 0;
//Only travel the loop until n/2 , because l+r will never equal n
// if l or r > n/2
var limit = Math.floor(n/2);
for(var i=l; i<=r && i<=limit; ++i){
for(var j=i;j<=r;++j){
if(i+j == n){
++representations;
break;
}
}
}
return representations;
}
Given integers n, l and r, find the number of ways to represent n as a sum of two integers A and B such that l ≤ A ≤ B ≤ r.
First, consider that if n is even and letting x = n/2, we have at least one solution (x + x) if, and only if, l ≤ x ≤ r. If x isn't in that range then there is no solution, since either x < l and l + l > n or r < x and r + r < n.
That can be generalized to even or odd n: There is a solution if, and only, if: l ≤ floor(x) ≤ ceil(x) ≤ r. If we let A = floor(x) and B = ceil(x), that solution is A + B. Every other solution can be found by taking one step along the number line away from that point in each direction. (A - 1) + (B + 1) = A + B = n, therefore (A - 1) + (B + 1) is a solution as long as (A - 1) hasn't crossed the l boundary and (B + 1) hasn't crossed the r boundary. So, if you wanted a solution with only one loop, you could do something like this:
function countSumOfTwoRepresentations2(n, l, r) {
var x = n/2;
var A = Math.floor( x );
var B = Math.ceil( x );
for ( var count = 0; l <= A && B <= r; count++) {
A--;
B++;
}
return count;
}
But how many times does that loop iterate? Well, it iterates until one of the stopping conditions happens:
A becomes smaller than l
B becomes larger than r
If 1. happens first, then it iterates Math.floor( x ) - l + 1 times, whereas if 2. happens first it iterates r - Math.ceil( x ) + 1 (if both conditions happen on the same iteration, then Math.floor( x ) - l === r - Math.ceil( x )).
As long as there is a solution the loop iterates the smaller of Math.floor( x ) - l + 1 or r - Math.ceil( x ) + 1 times, which is where the coder got the answer Math.min(Math.floor(n / 2) - l, r - Math.ceil(n / 2)) + 1 from (after substituting x back for n/2 and pulling the + 1 out of each term and adding it after instead.
If there is no solution, EG. n = 10, l = 20, r = 20, that formula will give a negative result, but it should give 0 instead, which is why he added Math.max( result, 0 );.
For clarity, the coder's solution could be written as (still with no loops):
function countSumOfTwoRepresentations2(n, l, r) {
var x = n/2;
var A = Math.floor( x );
var B = Math.ceil( x );
// Every solution is of the form (A - i) + (B + i), where i is an integer >= 0
// How many values of i are valid for l <= (A - i)
var stepsA = A - l + 1;
// How many values of i are valid for (B + i) <= r
var stepsB = r - B + 1;
// If the formulas gave a negative amount of valid steps,
// there is no solution, so return 0
if ( stepsA < 0 || stepsB < 0 )
return 0;
// Otherwise, return the smaller valid amount of steps,
// that is the number of steps that are valid for both A and B
return Math.min(stepsA, stepsB);
}
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
I'm parsing a binary file in javascript that is storing two pieces of information per byte, one per nibble. The values are, of course, 0-16 and 0-16.
In all other parts of the file format, each byte represents one piece of information, so I have been using the following to successfully get the number values I need:
var num = str.charCodeAt(0) & 0xFF;
But I'm stuck at trying to figure out how to get the 0-16 value of the first nibble, and the same for the 2nd nibble from my single byte character "str".
Appreciate any help on this.
var num = str.charCodeAt(0) & 0xFF;
var nibble1 = num & 0xF;
var nibble2 = num >> 4;
You can do:
var num = str.charCodeAt(0);
var lower_nibble = (num & 0xF0) >> 4;
var higher_nibble = num & 0x0F;
How does it work?
Lets suppose the bit representation of num is abcdwxyz and we want to extract abcd as higher nibble and wxyz as lower nibble.
To extract the lower nibble we just mask the higher nibble by bitwise anding the number with 0x0F:
a b c d w x y z
&
0 0 0 0 1 1 1 1
---------------
0 0 0 0 w x y z = lower nibble.
To extract the higher nibble we first mask the lower nibble by bitwise anding with 0xF0 as:
a b c d w x y z
&
1 1 1 1 0 0 0 0
---------------
a b c d 0 0 0 0
and then we bitwise right- shift the result right 4 times to get rid of the trailing zeros.
Bitwise right shifting a variable 1 time will make it loose the rightmost bit and makes the left most bit zero:
a b c d w x y z
>> 1
----------------
0 a b c d w x y
Similarly bitwise right shifting 2 times will introduce result in :
a b c d w x y z
>> 2
----------------
0 0 a b c d w x
and bitwise right shift 4 times gives:
a b c d w x y z
>> 4
----------------
0 0 0 0 a b c d
as clearly seen the result is the higher nibble of the byte (abcd).
Since I'm favoriting this, I wanted to add some things I just wrote that might be useful. Perhaps others will find it useful as well.
Below's jsFiddle
Prototypes:
Number.prototype.fromCharCode = function () {return String.fromCharCode(this); };
String.prototype.byte = function (val){ var a = new Array();
for(var i=(val||0),n=val===0?0:this.length-1; i<=n; i++){
a.push(this.charCodeAt(i) & 0xFF);
}
return a;
};
String.prototype.HiNibble = function (val){
var b = this.byte(val);
var a = new Array();
for(var i=0,n=b.length-1; i<=n; i++){a.push(b[i] >> 4);}
return a;
};
String.prototype.LoNibble = function (val){
var b = this.byte(val);
var a = new Array();
for(var i=0,n=b.length-1; i<=n; i++){a.push(b[i] & 0xF);}
return a;
};
Example Calls:
var str = new String("aB");
console.log(str.byte()); // [ 97, 66 ]
console.log(str.HiNibble()); // [ 6, 4 ]
console.log(str.LoNibble()); // [ 1, 2 ]
console.log(str.byte(0)); // [ 97 ]
console.log(str.HiNibble(0)); // [ 6 ]
console.log(str.LoNibble(0)); // [ 1 ]
var bar = "c";
console.log(bar.byte()); // [ 99 ]
console.log(bar.HiNibble()); // [ 6 ]
console.log(bar.LoNibble()); // [ 3 ]
var foobar = (65).fromCharCode(); // from an integer (foobar=="A")
console.log(foobar.byte()); // [ 65 ]
console.log(foobar.HiNibble()); // [ 4 ]
console.log(foobar.LoNibble()); // [ 1 ]
Just added for possible help, but is not used in the above:
/* Useful function that I modified
Originally from: http://www.navioo.com/javascript/dhtml/Ascii_to_Hex_and_Hex_to_Ascii_in_JavaScript_1158.html
*/
function AscHex(x,alg){
hex = "0123456789ABCDEF";
someAscii = ' !"#$%&\''
+ '()*+,-./0123456789:;=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\'
+ ']^_`abcdefghijklmnopqrstuvwxyz{|}';
r = "";
if(alg=="A2H"){
for(var i=0,n=x.length;i<n;i++){
let=x.charAt(i);
pos=someAscii.indexOf(let)+32;
h16=Math.floor(pos/16);
h1=pos%16;
r+=hex.charAt(h16)+hex.charAt(h1);
}
}
if(alg=="H2A"){
for(var i=0,n=x.length;i<n;i++){
let1=x.charAt(2*i);
let2=x.charAt(2*i+1);
val=hex.indexOf(let1)*16+hex.indexOf(let2);
r+=someAscii.charAt(val-32);
}
}
return r;
}
console.log(AscHex('65','A2H')); // A
Convert the string to buffer and then nipples:
function bufferToNibbles(key) {
// this will convert ascii string to hex values
// buffer will get sequence of bytes
const buffer = Buffer.from(key);
const nibbles = [];
for (let i = 0; i < buffer.length; i++) {
let q = i * 2;
nibbles[q] = buffer[i] >> 4;
++q;
nibbles[q] = buffer[i] % 16;
}
return nibbles;
}