For example digits=4 means if input is 7 need output 7999, for 83 output should be 8399, for 9 output should be 9999. Want to add trailing 9 based on digits
You could take the stringes number and pad the needed values.
function nines(value, digits) {
return +value.toString().padEnd(digits, 9);
}
console.log(nines(83, 4));
A numerical version
function nines(value, digits) {
while (value < 10 ** (digits - 1)) value = value * 10 + 9;
return value;
}
console.log(nines(83, 4));
console.log(nines(2, 1));
console.log(nines(2, 2));
One thing you may be able to do is to multiply the input number by a power of 10 in order to add extra digits of 0 to the end, and then use addition to add 9 into each of those newly created digits.
For example:
Input - 7
7 * 1000 -> 7000 (NOTE: 1000 is a power of 10: 10^3)
7000 + (100 * 9) + (10 * 9) + (1 * 9) = 7999
Input
83 * 100 -> 8300 (NOTE: 100 is a power of 10: 10^2)
8300 + (10 * 9) + (1 * 9) = 8399
Not entirely sure if this is what you want
trailNines(number) {
let numberString = number.toString();
let result = '';
if(numberString.length === 4){
result = number.toString();
}
if(numberString.length === 3) {
result = number.toString() + '9';
}
if(numberString.length === 2) {
result = number.toString() + '99';
}
if(numberString.length === 1) {
result = number.toString() + '999';
}
return parseInt(result);
}
Related
const reversedNum = num =>
parseFloat(num.toString().split('').reverse().join('')) * Math.sign(num)
console.log(reversedNum(456))
Couldn't figure it out how to write code in order to sum 654 + 456
Thank You very much!
const reversedNum = num => num + +num.toString().split('').reverse().join('')
You can return sum of num and reversedNum inside a function.
const sumOfNumAndReversedNum= num => {
const reversedNum = parseFloat(num.toString().split('').reverse().join('')) * Math.sign(num)
return num + reversedNum
}
let userNumber = 456
console.log(sumOfNumAndReversedNum(userNumber))
You can write a more performant way of reversing the number than turning it into a string, flipping it, and turning it back into an integer.
One option is to go through the number backwards by popping off the last integer (e.g., 123 % 10 === 3) and adding it to your newly reversed number. You'll also need to multiply your reversed number by 10 in each iteration to move you to the next degree.
For example, given the number 123:
123 % 10 = 3;
123 /= 10 = 12;
0 * 10 + 3 = 3;
1 % 10 = 2;
12 /= 10 = 1;
3 * 10 + 2 = 32
1 % 10 = 1;
1 /= 10 = 0;
32 * 10 + 1 = 321
This method will also automatically take care of negative numbers for you, leaving you something like:
function reverse(num) {
let reversed = 0;
while (num !== 0) {
const popped = num % 10;
num = parseInt(num / 10);
if (reversed > Number.MAX_VALUE / 10 || (reversed === Number.MAX_VALUE / 10 && popped > 7)) return 0;
if (reversed < Number.MIN_VALUE / 10 || (reversed === Number.MIN_VALUE / 10 && popped < -8)) return 0;
reversed = reversed * 10 + popped;
}
return reversed;
}
Now you can simply call:
console.log(123 + reverse(123))
const reversedNum = num =>
Number(num.toString().split('').reverse().join(''))
console.log(reversedNum(456))
Do it!
Im working on javascript problem code:
function randomNumberInt() {
return Math.floor(Math.random() * (1000 - 100 + 1) + 100);
}
You can use this function:
function genRandom() {
const digitHundreds = Math.floor(Math.random() * 9) + 1;
let digitTens = Math.floor(Math.random() * 9);
if (digitTens >= digitHundreds) digitTens++;
let digitUnits = Math.floor(Math.random() * 8);
if (digitUnits >= digitHundreds || digitUnits >= digitTens) digitUnits++;
if (digitUnits >= digitHundreds && digitUnits >= digitTens) digitUnits++;
return digitHundreds * 100 + digitTens * 10 + digitUnits;
}
console.log(genRandom());
Here digiHundreds, digitTens and digitUnits are the three digits of the number to generate.
digiHundreds has 9 choices: 1..9 (it cannot be 0)
digitTens has 10 choices, but excluding digiHundreds, so we choose from 0..8 and add 1 if it is greater or equal to digiHundreds
digitUnits has 10 choices, but excluding digiHundreds and digitTens, so we choose from 0..7 and add 1 if is greater or equal to either digiHundreds or digitTens, and add 1 more if it is greater or equal than both.
This process guarantees that the three digits are distinct. Combining the three digits to a number is a matter of multiplying them with the correct power of 10.
Fill the array untill the length is 3 and then join.
function getRandomArbitrary(min, max) {
return Math.floor(Math.random() * (max - min) + min) + 1;
}
function randomNumberInt() {
const result = [];
while (result.length !== 3) {
let random = getRandomArbitrary(0, 9);
if (!result.includes(random)) result.push(random);
// To check if the first no is not zero
if (result.length === 1 && random === 0) result.pop();
}
return parseInt( result.join("") );
}
const result = randomNumberInt();
console.log(result);
Decide each number separately.
First get last digit (any 0-9).
Then second (any 0-9, but not first).
Then the first digit (any 0-9, but not first, second, or 0).
function range(n) {
return [...Array(n).keys()] // returns [0,1,2,...,n-1]
}
function randomFromArray(arr) {
return arr[Math.floor(Math.random() * arr.length)]
}
function randomNumberInt() {
const digits = range(10) // or [...Array(10).keys()] if u do not want to declare range function
const lastDigit = randomFromArray(digits)
const possibleSecondDigits = digits.filter((n) => n !== lastDigit)
const secondDigit = randomFromArray(possibleSecondDigits)
const possibleFirstDigits = possibleSecondDigits.filter((n) => n !== 0 && n !== secondDigit)
const firstDigit = randomFromArray(possibleFirstDigits)
return firstDigit * 100 + secondDigit * 10 + lastDigit
}
console.log(randomNumberInt())
console.log(randomNumberInt())
console.log(randomNumberInt())
console.log(randomNumberInt())
console.log(randomNumberInt())
I want to generate the value being searched by the position entered in the check. For example, if 20 is entered, the function should generate numbers starting from 0 and continue in ascending order until 20 digits are created, then output the value of the 20th digit in the generated number string (01234567891011121314), which is 4.
I tried this below, however it is not efficient when it comes to numbers like 1,000,000,000,
[...Array(5).keys()]; output => [0, 1, 2, 3, 4]
Edit this post to clarify I am trying to get a more efficient solution.
Here I am trying to get the answer for long numbers(1,000,000,000) in below one second.
I already have a solution but it takes more than 1 second.
[...Array(5).keys()].join("")[4]; output => 4
This is nearly identical to the Champernowne constant.
A solution from math.stackexchange is:
(Stack Overflow doesn't support MathJax, unfortunately)
The first step is to find what decade you are in. There are 9 digits from the 1 digit numbers, 2⋅90=180 digits from the 2 digit numbers for a total of 189, and generally n⋅9⋅10n−1 from the n digit numbers. Once you have found the decade, you can subtract the digits from the earlier decades. So if you want the 765th digit, the first 189 come from the first and second decades, so we want the 576th digit of the 3 digit numbers. This will come in the ⌈5763⌉=192nd number, which is 291. As 576≡3(mod3), the digit is 1
Programatically:
const getDigit = (target) => {
let i = 0;
let xDigitNumbers = 1; // eg 1 digit numbers, 2 digit numbers
let digitsSoFar = 1;
while (true) {
const digitsThisDecade = xDigitNumbers * 9 * 10 ** (xDigitNumbers - 1);
if (digitsSoFar + digitsThisDecade > target) {
// Then this is the "decade" in which the target digit is
// digitIndexThisDecade: eg, starting from '100101102', to find the last '1' in '101', digitIndexThisDecade will be 6
const digitIndexThisDecade = target - digitsSoFar;
// numIndexThisDecade: this identifies the index of the number in the decade
// eg, starting from '100101102', this could be index 2 to correspond to 101 (one-indexed)
const numIndexThisDecade = Math.floor(digitIndexThisDecade / xDigitNumbers);
// decadeStartNum: the number right before the decade starts (0, 9, 99, 999)
const decadeStartNum = 10 ** (xDigitNumbers - 1);
// num: the number in which the target index lies, eg 101
const num = decadeStartNum + numIndexThisDecade;
// digitIndexInNum: the digit index in num that the target is
// eg, for 101, targeting the last '1' will come from a digitIndexInNum of 2 (zero-indexed)
const digitIndexInNum = digitIndexThisDecade % xDigitNumbers;
return String(num)[digitIndexInNum]
}
digitsSoFar += digitsThisDecade;
xDigitNumbers++;
}
};
for (let i = 0; i < 1000; i++) {
document.write(`${i}: ${getDigit(i)}<br>`);
}
Here's a simple approach without using arrays.
let N = 1000000000, digitsCount = 0, currentNumber = 0;
console.time('Took time: ');
const digits = (x)=>{
if(x<10)
return 1;
if(x<100)
return 2;
if(x<1000)
return 3;
if(x<10000)
return 4;
if(x<100000)
return 5;
if(x<1000000)
return 6;
if(x<10000000)
return 7;
if(x<100000000)
return 8;
if(x<1000000000)
return 9;
return 10; // Default
}
while(true){
digitsCount += digits(currentNumber);
if(digitsCount >= N)
break;
currentNumber++;
}
console.timeEnd('Took time: ');
console.log(String(currentNumber)[N-digitsCount+digits(currentNumber)-1])
Output (The execution time may differ for you but it'll be under 1 second(or 1000ms).)
Took time: : 487.860ms
9
i used .join("") to convert the array to string '01234567891011121314151617181920'
then access the Nth number by Indexing string
N=20;
console.log ( [...Array(N+1).keys()].join("")[N-1] ) //OUTPUT 4
EDIT:i think ther's a solution which is you don't need to create array at all😎
its a mathematical formula
Blockquote
In my Solution , we don't need big iterations and loops...
But This Solution is Big for simple understanding...
I made it for upto 6 digits , and its very efficient...and can be made for any number of digits... And can even be reduced to small functions , but that would get too complex to understand...
So , Total numbers for Given Digits :
For 1 Digit Numbers , They are 10 (0 to 9)....
For 2 Digit Numbers , They are 9*10 => 90 , and total Digits ==> 90*2 ==> 180...
For 3 Digit Numbers , 9*10*10 => 900 , and total Digits ==> 90*3 ==> 2700...
For 4 Digit Numbers , 9*10*10*10 => 9000 , and total Digits ==> 9000*4 ==> 36000...
A function to get Total Digits for a given specified (Number of Digits)
let totalDigits = n => {
if (n == 1) return 10;
return 9 * (10 ** (n - 1)) * n;
}
Now , we set a Range of position for different Digits ,
for 1 Digit , its between 1 and 10....
for 2 Digits , It's Between 11(1+10) and 190(180+10)...(position of 1 in 10 is 11 , and Second 9 in 99 is 190)...
for 3 Digits , It's Between 191(1+10+180) and 2890(2700+180+10)...And so on
for n Digit , Function to get Range is
// This function is used to find Range for Positions... Eg : 2 digit Numbers are upto Position 190...(Position 191 is "100" first digit => 1 )
let digitN = n => {
if (n == 1) return totalDigits(1);
return digitN(n - 1) + totalDigits(n);
}
// To Finally set Ranege for a Given Digit Number... for 1 its [1,10] , for 2 its [11,190]
let positionRange = n => {
if (n == 1) return [1, 10];
else return [digitN(n - 1), digitN(n)]
}
So Final Solution is
// This Function tells the total number of digits for the given digit... Eg : there are 10 one digit Numbers , 180 Two Digit Numbers , 2700 3 Digit Numbers
let totalDigits = n => {
if (n == 1) return 10;
return 9 * (10 ** (n - 1)) * n;
}
// This function is used to find Range for Positions... Eg : 2 digit Numbers are upto Position 190...(Position 191 is "100" first digit => 1 )
let digitN = n => {
if (n == 1) return totalDigits(1);
return digitN(n - 1) + totalDigits(n);
}
// To Finally set Ranege for a Given Digit Number... for 1 its [1,10] , for 2 its [11,190]
let positionRange = n => {
if (n == 1) return [1, 10];
else return [digitN(n - 1), digitN(n)]
}
// A simple Hack to get same value for Different Consecutive Numbers , (0.3 or 0.6 or 0.9 or 1 return 1)
let getDigit = n => {
if (dataType(n) == "float") {
n = Math.floor(n);
n++;
}
return n;
}
// To check for Float or Integer Values
function dataType(x) {
if (Math.round(x) === x) {
return 'integer';
}
return 'float';
}
function f(position) {
let result, charInd, temp;
if ((position >= positionRange(1)[0]) && (position <= positionRange(1)[1])) { // Positions 1 to 10 (1 Digit Numbers)
result = position - 1;
charInd = 0
}
if ((position > positionRange(2)[0]) && (position <= positionRange(2)[1])) { // Positions 11 to 190 (2 Digit Numbers)
temp = (position - 10) / 2;
temp = getDigit(temp);
result = temp + 9;
charInd = (position - 11) % 2
}
if ((position > positionRange(3)[0]) && (position <= positionRange(3)[1])) { // Positions 191 to 2890 (3 Digit Numbers)
temp = (position - 190) / 3;
temp = getDigit(temp);
result = temp + 99;
charInd = (position - 191) % 3
}
if ((position > positionRange(4)[0]) && (position <= positionRange(4)[1])) { // Positions 2891 to 38890 (4 Digit Numbers)
temp = (position - 2890) / 4;
temp = getDigit(temp);
result = temp + 999;
charInd = (position - 2891) % 4
}
if ((position > positionRange(5)[0]) && (position <= positionRange(5)[1])) { // Positions 38890 to 488890 (5 Digit Numbers)
temp = (position - 38890) / 5;
temp = getDigit(temp);
result = temp + 9999;
charInd = (position - 38891) % 5
}
if ((position > positionRange(6)[0]) && (position <= positionRange(6)[1])) { // Positions 488890 to 5888890 (6 Digit Numbers)
temp = (position - 488890) / 6 ;
temp = getDigit(temp);
result = temp + 99999;
charInd = (position - 488891) % 6
}
finalChar = String(result)[charInd];
console.log("Given Position => ", position, " Result Number => ", result, "Char Index ==> ", charInd, "Final Char => ", finalChar);
}
let d1 = Date.now();
f(138971); // Given Position => 138971 Result Number => 30016 Char Index ==> 0 Final Char => 3
let d2 = Date.now();
console.log(d2-d1) ; // 351
I want to generate the value being searched by the position entered in the check. For example, if 20 is entered, the function should generate numbers starting from 0 and continue in ascending order until 20 digits are created, then output the value of the 20th digit in the generated number string (01234567891011121314), which is 4.
I tried this below, however it is not efficient when it comes to numbers like 1,000,000,000,
[...Array(5).keys()]; output => [0, 1, 2, 3, 4]
Edit this post to clarify I am trying to get a more efficient solution.
Here I am trying to get the answer for long numbers(1,000,000,000) in below one second.
I already have a solution but it takes more than 1 second.
[...Array(5).keys()].join("")[4]; output => 4
This is nearly identical to the Champernowne constant.
A solution from math.stackexchange is:
(Stack Overflow doesn't support MathJax, unfortunately)
The first step is to find what decade you are in. There are 9 digits from the 1 digit numbers, 2⋅90=180 digits from the 2 digit numbers for a total of 189, and generally n⋅9⋅10n−1 from the n digit numbers. Once you have found the decade, you can subtract the digits from the earlier decades. So if you want the 765th digit, the first 189 come from the first and second decades, so we want the 576th digit of the 3 digit numbers. This will come in the ⌈5763⌉=192nd number, which is 291. As 576≡3(mod3), the digit is 1
Programatically:
const getDigit = (target) => {
let i = 0;
let xDigitNumbers = 1; // eg 1 digit numbers, 2 digit numbers
let digitsSoFar = 1;
while (true) {
const digitsThisDecade = xDigitNumbers * 9 * 10 ** (xDigitNumbers - 1);
if (digitsSoFar + digitsThisDecade > target) {
// Then this is the "decade" in which the target digit is
// digitIndexThisDecade: eg, starting from '100101102', to find the last '1' in '101', digitIndexThisDecade will be 6
const digitIndexThisDecade = target - digitsSoFar;
// numIndexThisDecade: this identifies the index of the number in the decade
// eg, starting from '100101102', this could be index 2 to correspond to 101 (one-indexed)
const numIndexThisDecade = Math.floor(digitIndexThisDecade / xDigitNumbers);
// decadeStartNum: the number right before the decade starts (0, 9, 99, 999)
const decadeStartNum = 10 ** (xDigitNumbers - 1);
// num: the number in which the target index lies, eg 101
const num = decadeStartNum + numIndexThisDecade;
// digitIndexInNum: the digit index in num that the target is
// eg, for 101, targeting the last '1' will come from a digitIndexInNum of 2 (zero-indexed)
const digitIndexInNum = digitIndexThisDecade % xDigitNumbers;
return String(num)[digitIndexInNum]
}
digitsSoFar += digitsThisDecade;
xDigitNumbers++;
}
};
for (let i = 0; i < 1000; i++) {
document.write(`${i}: ${getDigit(i)}<br>`);
}
Here's a simple approach without using arrays.
let N = 1000000000, digitsCount = 0, currentNumber = 0;
console.time('Took time: ');
const digits = (x)=>{
if(x<10)
return 1;
if(x<100)
return 2;
if(x<1000)
return 3;
if(x<10000)
return 4;
if(x<100000)
return 5;
if(x<1000000)
return 6;
if(x<10000000)
return 7;
if(x<100000000)
return 8;
if(x<1000000000)
return 9;
return 10; // Default
}
while(true){
digitsCount += digits(currentNumber);
if(digitsCount >= N)
break;
currentNumber++;
}
console.timeEnd('Took time: ');
console.log(String(currentNumber)[N-digitsCount+digits(currentNumber)-1])
Output (The execution time may differ for you but it'll be under 1 second(or 1000ms).)
Took time: : 487.860ms
9
i used .join("") to convert the array to string '01234567891011121314151617181920'
then access the Nth number by Indexing string
N=20;
console.log ( [...Array(N+1).keys()].join("")[N-1] ) //OUTPUT 4
EDIT:i think ther's a solution which is you don't need to create array at all😎
its a mathematical formula
Blockquote
In my Solution , we don't need big iterations and loops...
But This Solution is Big for simple understanding...
I made it for upto 6 digits , and its very efficient...and can be made for any number of digits... And can even be reduced to small functions , but that would get too complex to understand...
So , Total numbers for Given Digits :
For 1 Digit Numbers , They are 10 (0 to 9)....
For 2 Digit Numbers , They are 9*10 => 90 , and total Digits ==> 90*2 ==> 180...
For 3 Digit Numbers , 9*10*10 => 900 , and total Digits ==> 90*3 ==> 2700...
For 4 Digit Numbers , 9*10*10*10 => 9000 , and total Digits ==> 9000*4 ==> 36000...
A function to get Total Digits for a given specified (Number of Digits)
let totalDigits = n => {
if (n == 1) return 10;
return 9 * (10 ** (n - 1)) * n;
}
Now , we set a Range of position for different Digits ,
for 1 Digit , its between 1 and 10....
for 2 Digits , It's Between 11(1+10) and 190(180+10)...(position of 1 in 10 is 11 , and Second 9 in 99 is 190)...
for 3 Digits , It's Between 191(1+10+180) and 2890(2700+180+10)...And so on
for n Digit , Function to get Range is
// This function is used to find Range for Positions... Eg : 2 digit Numbers are upto Position 190...(Position 191 is "100" first digit => 1 )
let digitN = n => {
if (n == 1) return totalDigits(1);
return digitN(n - 1) + totalDigits(n);
}
// To Finally set Ranege for a Given Digit Number... for 1 its [1,10] , for 2 its [11,190]
let positionRange = n => {
if (n == 1) return [1, 10];
else return [digitN(n - 1), digitN(n)]
}
So Final Solution is
// This Function tells the total number of digits for the given digit... Eg : there are 10 one digit Numbers , 180 Two Digit Numbers , 2700 3 Digit Numbers
let totalDigits = n => {
if (n == 1) return 10;
return 9 * (10 ** (n - 1)) * n;
}
// This function is used to find Range for Positions... Eg : 2 digit Numbers are upto Position 190...(Position 191 is "100" first digit => 1 )
let digitN = n => {
if (n == 1) return totalDigits(1);
return digitN(n - 1) + totalDigits(n);
}
// To Finally set Ranege for a Given Digit Number... for 1 its [1,10] , for 2 its [11,190]
let positionRange = n => {
if (n == 1) return [1, 10];
else return [digitN(n - 1), digitN(n)]
}
// A simple Hack to get same value for Different Consecutive Numbers , (0.3 or 0.6 or 0.9 or 1 return 1)
let getDigit = n => {
if (dataType(n) == "float") {
n = Math.floor(n);
n++;
}
return n;
}
// To check for Float or Integer Values
function dataType(x) {
if (Math.round(x) === x) {
return 'integer';
}
return 'float';
}
function f(position) {
let result, charInd, temp;
if ((position >= positionRange(1)[0]) && (position <= positionRange(1)[1])) { // Positions 1 to 10 (1 Digit Numbers)
result = position - 1;
charInd = 0
}
if ((position > positionRange(2)[0]) && (position <= positionRange(2)[1])) { // Positions 11 to 190 (2 Digit Numbers)
temp = (position - 10) / 2;
temp = getDigit(temp);
result = temp + 9;
charInd = (position - 11) % 2
}
if ((position > positionRange(3)[0]) && (position <= positionRange(3)[1])) { // Positions 191 to 2890 (3 Digit Numbers)
temp = (position - 190) / 3;
temp = getDigit(temp);
result = temp + 99;
charInd = (position - 191) % 3
}
if ((position > positionRange(4)[0]) && (position <= positionRange(4)[1])) { // Positions 2891 to 38890 (4 Digit Numbers)
temp = (position - 2890) / 4;
temp = getDigit(temp);
result = temp + 999;
charInd = (position - 2891) % 4
}
if ((position > positionRange(5)[0]) && (position <= positionRange(5)[1])) { // Positions 38890 to 488890 (5 Digit Numbers)
temp = (position - 38890) / 5;
temp = getDigit(temp);
result = temp + 9999;
charInd = (position - 38891) % 5
}
if ((position > positionRange(6)[0]) && (position <= positionRange(6)[1])) { // Positions 488890 to 5888890 (6 Digit Numbers)
temp = (position - 488890) / 6 ;
temp = getDigit(temp);
result = temp + 99999;
charInd = (position - 488891) % 6
}
finalChar = String(result)[charInd];
console.log("Given Position => ", position, " Result Number => ", result, "Char Index ==> ", charInd, "Final Char => ", finalChar);
}
let d1 = Date.now();
f(138971); // Given Position => 138971 Result Number => 30016 Char Index ==> 0 Final Char => 3
let d2 = Date.now();
console.log(d2-d1) ; // 351
I have tried this
function binToDec(num) {
let dec = 0;
for(let i = 0; i < num.length; i++) {
if(num[num.length - (i + 1)] === '1') {
dec += 2 ** i;
}
}
return dec;
}
console.log(binToDec('1010'));
this code is not mine and it works but i want to know how it converts the binary number to decimal and it will be very helpful is you could tell me another way to do it.
I have also tried this
function binToDec(num) {
let bin = parseInt(num, 2);
return bin;
}
console.log(binToDec(1010));
I know this also work but i am not looking for this answer.
thank you for your help.
I just starts with the last character of the string and adds the value of this position to the result.
string dec
------ -------
1010 0
0 0
1 0 + 2
0 2
1 2 + 8
------ ------
10
function binToDec(num) {
let dec = 0;
for (let i = 0; i < num.length; i++) {
if (num[num.length - (i + 1)] === '1') {
dec += 2 ** i;
}
}
return dec;
}
console.log(binToDec('1010')); // 10
Another way is to start with the left side of the sting and
multiply the converted value by the base (2) and
add the value of the string.
The result is now the converted number. This works for all bases, as long as the value at the index is converted to a number.
function binToDec(num) {
let dec = 0;
for (let i = 0; i < num.length; i++) {
dec *= 2;
dec += +num[i];
}
return dec;
}
console.log(binToDec('1101')); // 13
Explanation
Think of how base 10 works.
909 = 900 + 9
= (9 * 100) + (0 * 10) + (9 * 1)
= (9 * 10**2) + (0 * 10**1) + (9 * 10**0)
As you can see, a natural number in base 10 can be seen as a sum where each term is in the form of:
digit * base**digit_position
This is true for any base:
base 2 : 0b101 = (0b1 * 2**2) + (0b0 * 2**1) + (0b1 * 2**0)
base 16 : 0xF0F = (0xF * 16**2) + (0x0 * 16**1) + (0xF * 16**0)
Therefore, here is a possible abstraction of a natural number:
function natural_number (base, digits) {
var sum = 0;
for (var i = 0; i < digits.length; i++) {
digit = digits[i];
digit_position = digits.length - (i + 1);
sum += digit * base**digit_position;
}
return sum;
}
> | natural_number(2, [1, 0, 1]) // 1 * 2**2 + 1 * 2**0
< | 5
> | natural_number(10, [1, 0, 1]) // 1 * 10**2 + 1 * 10**0
< | 101
> | natural_number(16, [1, 0, 1]) // 1 * 16**2 + 1 * 16**0
< | 257
Your own function takes only binary numbers (base 2). In this case digit can be either 0 or 1, that's all. We know that it's useless to multiply something by 0 or 1, so the addition can be replaced with:
if (digit === 1) {
sum += 2**digit_position;
}
Which is the equivalent of:
if (num[num.length - (i + 1)] === '1') {
dec += 2 ** i;
}
Do you get it? :-)
Alternative
You don't feel confortable with the exponentiation operator (**)? There is a workaround. Did you ever notice that multiplying a number by 10 is nothing more than shifting its digits one time to the left?
909 * 10 = 9090
Actually, shifting a number to the left boils down to multiplying this number by its base:
number *= base
This is true for any base:
base 2 : 0b11 * 2 = 0b110
base 16 : 0xBEE * 16 + 0xF = 0xBEE0 + 0xF = 0xBEEF
Based on this, we can build an algorithm to convert an array of digits into a number. A trace of execution with [9,0,9] in base 10 as input would look like this:
init | 0 | n = 0
add 9 | 9 | n += 9
shift | 90 | n *= 10
add 0 | 90 | n += 0
shift | 900 | n *= 10
add 9 | 909 | n += 9
Here is a possible implementation:
function natural_number (base, digits) {
var n = 0;
for (var i = 0; i < digits.length; i++) {
n += digits[i];
if (i + 1 < digits.length) {
n *= base;
}
}
return n;
}
Of course this function works the same as before, and there is a good reason for that. Indeed, unroll the for loop that computes [9,0,9] in base 10, you get this:
return ((0 + 9) * 10 + 0) * 10 + 9;
Then expand this expression:
((0 + 9) * 10 + 0) * 10 + 9
= (0 + 9) * 10 * 10 + 0 * 10 + 9
= 9 * 10 * 10 + 0 * 10 + 9
= 9 * 10**2 + 0 * 10**1 + 9 * 10**0
Do you recognize the equation discussed earlier? :-)
Bonus
Reverse function:
function explode_natural_number (base, number) {
var remainder, exploded = [];
while (number) {
remainder = number % base;
exploded.unshift(remainder);
number = (number - remainder) / base;
}
return exploded.length ? exploded : [0];
}
> | explode_natural_number(2, 5)
< | [1, 0, 1]
> | explode_natural_number(3, 5) // base 3 (5 = 1 * 3**1 + 2 * 3**0) :-)
< | [1, 2]
> | explode_natural_number(16, natural_number(16, [11, 14, 14, 15])) // 0xBEEF
< | [11, 14, 14, 15]
String to number and number to string:
function parse_natural_number (number, base) {
var ZERO = 48, A = 65; // ASCII codes
return natural_number(base, number.split("").map(function (digit) {
return digit.toUpperCase().charCodeAt(0);
}).map(function (code) {
return code - (code < A ? ZERO : A - 10);
}));
}
function stringify_natural_number (number, base) {
var ZERO = 48, A = 65; // ASCII codes
return String.fromCharCode.apply(
String, explode_natural_number(base, number).map(function (digit) {
return digit + (digit < 10 ? ZERO : A - 10);
})
);
}
> | stringify_natural_number(parse_natural_number("48879", 10), 16)
< | "BEEF"
> | parse_natural_number("10", 8)
< | 8
More levels of abstraction for convenience:
function bin_to_dec (number) {
return parse_natural_number(number, 2);
}
function oct_to_dec (number) {
return parse_natural_number(number, 8);
}
function dec_to_dec (number) {
return parse_natural_number(number, 10);
}
function hex_to_dec (number) {
return parse_natural_number(number, 16);
}
function num_to_dec (number) {
switch (number[0] + number[1]) {
case "0b" : return bin_to_dec(number.slice(2));
case "0x" : return hex_to_dec(number.slice(2));
default : switch (number[0]) {
case "0" : return oct_to_dec(number.slice(1));
default : return dec_to_dec(number);
}
}
}
> | oct_to_dec("10")
< | 8
> | num_to_dec("010")
< | 8
> | 010 // :-)
< | 8
function dec_to_bin (number) {
return stringify_natural_number(number, 2);
}
> | dec_to_bin(8)
< | "1000"