Always display number with 3 digits and descriptor - javascript

Using Javascript, I want to format a number to always display 3 digits, along with it's proper identifier (ex: Million, Thousand). If under 100,000, the number should only show the "thousands" digits
All numbers will be integers above zero, and the highest numbers will be in the trillions.
A few examples of what I'm looking for:
1 Thousand
13 Thousand
627 Thousand
2.85 Million
67.9 Million
153 Million
9.52 Billion
etc...
All of the solutions I tried ended up becoming spaghetti code, and I am hoping someone can find a clean, smart solution.
EDIT:
I ended up using part of RobG's solution, but worked out the specifics on my own. I added rounding as well
function getNumberName(num) {
var numNames = ['', 'Thousand', 'Million', 'Billion', 'Trillion'];
num = num.toString();
var len = num.length - 1;
return numNames[len / 3 | 0];
}
function test(num) {
var numStr = num.toString();
if (num < 1000) {
return numStr;
} else if (num < 1000000) {
return numStr.slice(0, -3) + "," + numStr.slice(-3);
}
numStr = Math.round(parseFloat(numStr.slice(0, 3) + "." + numStr[3])).toString() + Array(numStr.slice(3).length + 1).join("0");
var remainder = numStr.length % 3;
var before = numStr.slice(0, remainder);
var after = numStr.slice(remainder, 3);
var sep = "";
if (before.length) {
sep = ".";
}
return before + sep + after + " " + getNumberName(num);
}
var nums = [0, 1, 12, 123, 1234, 12345, 123456, 1237567, 12325678, 123856789, 123e7, 125e8, 123.6e9, 123e10];
nums.forEach(function(num) {
document.write(num + ": $" + test(num) + "<br/>");
});

For integers, you can try shortening the number to the required number of places, then adding a name, e.g.
// For integers
function getNumberName(num) {
var numNames = ['','Thousand','Million','Billion'];
var num = num.toString()
var len = num.length - 1;
var pow = numNames[len/3 | 0];
return pow;
}
// For integers
function abbreviateNumber(num, places) {
places = places || 0;
var len = num.toString().length - 1;
var pow = len/3 | 0
return (num < 1000? num : num/Math.pow(10, pow*3)).toFixed(places);
}
function getNumberAbbr(num, places) {
return abbreviateNumber(num, places) + ' ' + getNumberName(num);
}
var nums = [0,1,12,123,1234,12345,123456,1234567,12345678,123456789,123e7]
nums.forEach(function(num) {
console.log(num + ' : ' + getNumberAbbr(num,1));
});
The above is not complete. There should be a limit applied so that beyond, say 1 trillion, it stops shortening the number.

There might be a better way but this will work:
function getTextNums(number) {
if ((number/1000000) < 1) {
var n = number.toString();
var first3 = n.substring(0, 3);
console.log(first3 + "Thousand");
} else if((number/1000000000) < 1) {
var n = number.toString();
var first3 = n.substring(0, 3);
console.log(first3 + "Million");
} else if((number/1000000000000) < 1) {
var n = number.toString();
var first3 = n.substring(0, 3);
console.log(first3 + "Billion");
} else if((number/1000000000000000) < 1) {
var n = number.toString();
var first3 = n.substring(0, 3);
console.log(first3 + "Trillion");
} else {
}
}
getTextNums(4533544433000)

Related

while loop test case errors

The question as per the practice course is :
Write a JavaScript program to find the maximum integer n such that (1 + 2 + ... + n <= given integer ) is true. For eg. If a given integer is 10, value of maximum integer n is 4 so that 1+2+3+4 <= 10 is true. Your output code should be in the format console.log("Value of n is ", variableName)
My code is :
var num = prompt("Enter a number");
function test(x) {
var sum = 1,
n = 1,
a = 0;
while (sum <= x) {
sum += n;
n = n + 1;
a += 1;
}
return a;
}
var output = test(num);
console.log("Result is :", output);
I'm getting the correct outputs as per the test cases I've entered(10-4,15-5,16-6,17-6) but the website says there is something wrong with the program.
What am i doing wrong?
Better answer than looping: exploit maths. Starting with Triangular number formula:
1 + 2 + ... + n = n * (n + 1) / 2
Thus, for input x, you need to find n such that
n * (n + 1) / 2 <= x
To solve this, we need to clean up the inequality, then use the quadratic equation formula:
n^2 + n <= 2x
n^2 + n - 2x <= 0
n <= (-1 + sqrt(1 + 8x)) / 2
as the final solution. e.g. for
x = 10: n <= (-1 + sqrt(81)) / 2; n <= 4
x = 16: n <= (-1 + sqrt(128)) / 2; n <= 5.156854249492381
Round the upper limit down, and you have the largest allowed integer. Translated into JavaScript:
function test(x) {
return Math.floor((Math.sqrt(8 * x + 1) - 1) / 2);
}
var num = prompt("Enter a number");
console.log("Result is :", test(num));
Consider if the passed value is 11. Then, the maximum integer n should be 4, because 1+2+3+4 < 11 is true, while 1+2+3+4+5 < 11 is false. Your current code outputs 5 for an input of 11, though, which is incorrect; your while loop is sometimes overshooting sum.
You also need to initialize sum to start at 0, not at 1.
Subtract one from a before returning it:
function test(x) {
var sum = 0,
n = 1,
a = 0;
while (sum <= x) {
sum += n;
n = n + 1;
a += 1;
console.log(a, sum);
}
return a - 1;
}
console.log(test(10));
console.log(test(11));
var num = prompt("Enter a number");
var output = test(num);
console.log("Result is :", output);
The code below should work for you. Basically, what I did was that if the input is 10, and your sum is 9, it will still go into the while loop. Then it will add n again and now your number is greater than your input (which is 10), but you still return it. Here what I did is that at the end of the while loop, if your sum is greater than your input, subtract one from a. That way it will still execute, but it will fix the problem.
Also another error I noticed was that sum started at 1, and n started at 1. You wanted 1+2+3+...+n, however using your previous method, you got 1+1+2+3+...+n.
var num = prompt("Enter a number");
function test(x) {
var sum = 0,
n = 1,
tempSum = 1,
a = 0;
while (sum <= x) {
sum += n;
n++;
a++;
if (sum > x) {
a--;
}
}
return a;
}
var output = test(num);
console.log("Result is :", output);
Your order of operation is a little funky; all you have to do is add the incrementor. The while false case will make sure the sum only passes over the number once. So when you return, reduce the number by one:
var num = prompt("Enter a number");
var output = test(num);
console.log("Result is :", output);
function test(num){
let sum = 0
let inc = 0
while(sum<=num)
sum+=++inc
return --inc;
}
This is a reduced version of your code, basically we increment first the number to add (n) in each iteration, and then we add it to the variable holding the sum. When the loop conditions evaluates to false you need to decrement one to n to get your value:
var num = prompt("Enter a number");
function test(x)
{
var sum = 0, n = 0;
while (sum <= x)
{
sum += (++n);
}
return --n;
}
var output = test(num);
console.log("Result is :", output);
I think this will work for you:
var num = prompt("Enter a number");
function test(x) {
var sum = 1,
n = 0;
while ((sum+n) <= x) {
n = n + 1;
sum += n;
}
return n;
}
var output = test(num);
console.log("Result is :", output);
Try below function to find max Number
function maxNumber(a){
var i=1,sum=0,maxNumber=0;
while(sum<=a) {
sum=sum+i;
if(sum<=a)
{
maxNumber=i;
}
i+=1;
}
return maxNumber;
}
doubled checked condition sum<=a to preserve the previous loop value and if condition not satisfied that means current loop value is not useful so returned preserved value of previous loop
Output tested :
Below will help you get the job done.
var num = prompt("Enter a number");
function findMaxNumber(num){
var sum = 0;
var counter = 0;
while(sum < num){
if(sum + counter > num){
break; // Exit loop
}
sum = sum + counter;
counter++;
}
return --counter; // Loop will cause this to be 1 higher than the max int.
}
console.log('Result is: ' + findMaxNumber(num));

How can we get the number of all possible non-negative integers similar to a given non-negative integer by re-arranging it using javascript

Given a non-negative number say 1213, it should return 12 because there are 12 possible integers similar to 1213 i.e., 1123,1132,1213,1231,1312,1321,2113,2131,2311,312,3121 and 3211. Same with 10, it should return 1 and 12 should return 2 and if the number is 120 it should return 4 as combinations are 120,102,210,201.
You can use this formula to get the total number of unique permutations excluding permutations with leading zero.
Lets define some symbols:
n = Total Number of digits
z = Number of zeros
r1, r2, ..., rn = repetition count of digits with count > 1
fact(p) = factorial of number of p
Total permutations = (n - z) * fact(n - 1) / fact(r1) * fact(r2) * .... * fact(rn)
For example, for 1213,
n = 4, z = 0, r1 (digit 1) = 2
permutations = (4 - 0) * fact(4 - 1) / fact(2) = 4 * 6 / 2 = 12
You can easily convert this to program.
function factorial(n) {
if (n <=1)
return 1;
return n * factorial(n-1);
}
function getPermutations(number) {
var n = number.toString().split('').length;
var r = {};
number.toString().split('').forEach(function(digit){
r[digit] = r[digit] || 0;
r[digit] += 1;
});
var z = number.toString().split('').reduce(function(count, digit) {
return (digit === '0') ? count + 1 : count;
}, 0);
var denominator = Object.keys(r).map(function (key) { return r[key]; }).reduce(function(result, curr) {
return result * factorial(curr);
}, 1);
//console.log(n, r, z);
return (n - z) * factorial(n - 1) / denominator;
}
var result = getPermutations(1216);
console.log(result);
Note : This is basic implementation and would not be the most optimum. Also, factorial calculation involves large numbers and would probably fail for large inputs.
You are looking for an anagram algorithm :
This script find every anagram of a string then delete every number starting with zero :
var allAnagrams = function(arr) {
var anagrams = {};
arr.forEach(function(str) {
var recurse = function(ana, str) {
if (str === '')
anagrams[ana] = 1;
for (var i = 0; i < str.length; i++)
recurse(ana + str[i], str.slice(0, i) + str.slice(i + 1));
};
recurse('', str);
});
return Object.keys(anagrams);
}
var arr = ['120']; //declare your number
var anag = allAnagrams(arr); //send it to the function
for (var i in anag) { //delete leading 0
if((anag[i].charAt(0)) === '0' ) {
anag.splice(i);
}
}
console.log(anag); //print array
console.log(anag.length); // print length
Here the output will be :
["102", "120", "201", "210"]
4

How can I count the number of zero decimals in JavaScript?

How do I get the number of zero decimals behind the comma (but not the total)? So to illustrate an example:
0.00001 > 4
0.000015 > 4
0.0000105 > 4
0.001 > 2
I am looking for methods that are efficient (meaning that they optimize the calculation time).
You can use logarithms to find the magnitude of the number:
var x = 0.00195;
var m = -Math.floor( Math.log(x) / Math.log(10) + 1);
document.write(m); // outputs 2
Later versions of JavaScript have Math.log10, so it would be:
var x = 0.00195;
var m = -Math.floor( Math.log10(x) + 1);
document.write(m); // outputs 2
How using the base-10 logarithm of the numbers works:
x
Math.log10(x)
Math.floor(Math.log10(x) + 1 )
0.1
-1
0
0.01
-2
-1
0.015
-1.8239…
-1
0.001
-3
-2
0.00001
-5
-4
0.000015
-4.8239…
-4
0.0000105
-4.9788…
-4
Use a regex to match the number of zeros after a decimal point and then count them.
var zeros = float.toString().match(/(\.0*)/)[0].length - 1;
DEMO
Use this one:
function numberOfZeros(n) {
var c = 0;
while (!~~n) {
c++;
n *= 10;
}
return c - 1;
}
document.write(numberOfZeros(0.00065));
This code does the following: it multiplies the number by ten as long as it can be truncated to something not equal 0. The truncation operator "~~" is very performant, because it works with byte representation of the number directly.
It doesn't use any string operations and does exactly what you want: counts the zeros.
//my answer
function t1()
{
var num = 0.0000005323;
numOfZeroes = 0;
while(num < 1)
{
numOfZeroes++;
num *= 10;
}
}
//others
//Andrew Morton's answer
//https://stackoverflow.com/a/31002148/1115360
function t2()
{
var num = 0.0000005323;
var m = -Math.floor( Math.log10(num) + 1);
}
//Amy's Answer
//https://stackoverflow.com/a/31002087/4801298
function t3()
{
var r = 0.0000005323;
var count=0;
var splited = r.toString().split(".")[1];
for(var i=0;i<splited.length;i++)
{
if(splited[i]==0)
{
count++;
}
else
{
break;
}
}
}
//Ted's Answer
//https://stackoverflow.com/a/31002052/4801298
function t4()
{
var number = 0.0000005323;
var numberAsString = number.toString();
var decimalsAsString = numberAsString.substr(numberAsString.lastIndexOf('.')+1);
var leadingZeros = decimalsAsString.substr(0, decimalsAsString.lastIndexOf('0')+1).length;
}
//Bartłomiej Zalewski's answer
//https://stackoverflow.com/a/31001998/4801298
function t5()
{
var n = 0.0000005323;
var c = 0;
while (!~~n) {
c++;
n *= 10;
}
return c - 1;
}
//Andy 's answer
//https://stackoverflow.com/a/31002135/4801298
function t6()
{
var float = 0.0000005323;
var zeros = float.toString().match(/(\.0*)/)[0].length - 1;
}
//Praveen's answer
//https://stackoverflow.com/a/31002011/4801298
function t7()
{
var a = 0.0000005323;
return (a.toString().replace("0.", "").split("0").length - 1);
}
//benchmark function
function bench(func)
{
var times = new Array();
for(var t = 0; t < 100; t++)
{
var start = performance.now();
for(var i = 0; i < 10000; i++)
{
func();
}
var end = performance.now();
var time = end - start;
times.push(time);
}
var total = 0.0;
for(var i=0, l=times.length; i<l; i++)
total += times[i];
var avg = total / times.length;
return avg;
}
document.write('t1: ' + bench(t1) + "ms<BR>");
document.write('t2: ' + bench(t2) + "ms<BR>");
document.write('t3: ' + bench(t3) + "ms<BR>");
document.write('t4: ' + bench(t4) + "ms<BR>");
document.write('t5: ' + bench(t5) + "ms<BR>");
document.write('t6: ' + bench(t6) + "ms<BR>");
document.write('t7: ' + bench(t7) + "ms<BR>");
Note:
This would only work with numbers less than 1 of course. Otherwise, just remove numbers left of the decimal point first, like
num -= num % 1;
need to compare this to another way.
a while later...
I would like a better way to bench these function though. I might have my calculation wrong. I'm adding other peoples answers into the test. I'm now attempting to use the performance API
a bit later than before
AHA! Got it working. Here are some comparisons for you.
You can use something like this:
function num (a) {
return (a.toString().replace("0.", "").split("0").length - 1)
}
Here is a working example (a bit lengthy for clarity):
var number = 0.0004342;
var numberAsString = number.toString();
var decimalsAsString = numberAsString.substr(numberAsString.lastIndexOf('.')+1);
var leadingZeros = decimalsAsString.substr(0, decimalsAsString.lastIndexOf('0')+1).length;
// leadingZeros == 3
Convert the number in to a string and split it with the dot (.). Using the for loop to count the zeros occurrences.
var r = 0.0000107;
var count=0;
var splited = r.toString().split(".")[1];
for(var i=0;i<splited.length;i++)
{
if(splited[i]==0)
{
count++;
}
else
{
break;
}
}
console.log(count);
Node.js 9.0.0
I was looking for a solution without converting or the O(n) approach. Here is what solution I made by O(1).
Part of finding decimal by log – caught from #AndrewMorton, but it might be laggy with the divider: log(10) – 2.302585092994046.
Example
const normalize = (value, zeroCount) => {
const total = 10 ** zeroCount
const zeros = Math.floor(-Math.log10(value / total))
return value * (10 ** zeros)
}
Usage
normalize(1510869600, 13) // 1510869600000
normalize(1510869600, 10) // 1510869600

What's wrong with this even/odd Javascript?

I am trying to write a very simple JS program. I want it to generate 10 random numbers between 1 and 100 and display how many of them are even and how many are odd. I've been looking all over and I can't find why this isn't working. It's displaying 0 even numbers and 10 odd numbers, no matter the combination. What am I overlooking?
function main()
{
var number = 0;
var totalNumbers = 0;
var evenNumbers = 0;
var oddNumbers = 0;
document.write("Here are ten random numbers between 1 and 100:<br><br>");
while(totalNumbers < 10)
{
number = document.write((Math.floor((Math.random()* 100)+1)) + "<br>");
if(number % 2 == 0)
{
evenNumbers++;
}
else
{
oddNumbers++;
}
totalNumbers++;
}
document.write("<br><br>Even Numbers: " + evenNumbers + "<br>" +
"Odd Numbers: " + oddNumbers);
}
document.write() does not return a number. Store the number in a variable before calling document.write().
while(totalNumbers < 10)
{
var number = Math.floor((Math.random()* 100)+1;
document.write(number + "<br>");
if(number % 2 == 0)
{
evenNumbers++;
}
else
{
oddNumbers++;
}
totalNumbers++;
}

Replace fractions with fractions regular expressions, numbers with numbers regular expression

I've the following regular expressions that I want to run on the example input, to replace both numbers and fractions (I need to multiply them by a number that the user will choose):
numbersRegex = /[0-9]+(?:\.[0-9]*)?/g;
fractionsRegex = /((\d+)\/(\d+))/g;
The numbersRegex needs to run on lines containing numbers only (I marked them in the example input underneath using numbersRegex).
The fractionsRegex needs to run on lines containing fractions only (I marked them in the example input underneath using fractionsRegex).
I need them to be two different ones as the multiplication method is different, so I would like to run str.replace two times, one to multiply all fractions and the other to multiply all numbers.
Here is the example input:
1 1/2 oz. white rum (fractionsRegex)
1/2 lime, cut in 4 wedges (fractionsRegex)
10 mint leaves, fresh (numbersRegex)
2 tbsp. white sugar (numbersRegex)
1 cup ice cubes (numbersRegex)
1/2 cup club soda (fractionsRegex)
Is that possible?
Many thanks
UPDATE
This is the function I'm currently using (it needs to be cleaned up and I'm sure it can also be optimised):
function _increaseServings(target, initialServings, newServings) {
target.html(originalIngredientsHTML);
target.find('li').each(function(i) {
var currentLine = $(this).text();
var importantPart = currentLine.split(',');
var fractionsRegex = importantPart[0].match(/((\d+)\/(\d+))/g);
var lineHiddenFractions = importantPart[0] != null ? importantPart[0].replace(/([0-9]{1,})([\/]{1})([0-9]{1,})/g, "") : "";
var numbersRegex = lineHiddenFractions.match(/([0-9]+(?:\.[0-9]*)?)/g);
var result = {};
var strToReplace = '';
if (fractionsRegex == null && numbersRegex == null) return;
if (fractionsRegex !== null && fractionsRegex.length > 0) {
result.fraction = fractionsRegex[0];
strToReplace = result.fraction;
}
if (numbersRegex !== null && numbersRegex.length > 0) {
result.number = parseInt(numbersRegex[0]);
if(result.fraction) {
strToReplace = result.number + ' ' + strToReplace;
} else {
strToReplace = result.number;
}
}
if(result.fraction) {
var fraction = result.fraction.split('/');
if(result.number && result.fraction) {
result.decimal = parseInt(result.number) + parseInt(fraction[0]) / parseInt(fraction[1]);
} else {
result.decimal = parseInt(fraction[0]) / parseInt(fraction[1]);
}
} else {
result.decimal = parseInt(result.number);
}
result.stringToReplace = strToReplace;
var newValue = result.decimal * (newServings / initialServings);
if(newValue % 1 != 0) {
var values = String(newValue).split('.');
var checkValue = String(values[1]).slice(0,1);
var integerPart = Math.floor(newValue);
if(checkValue == 2) {
// 25
newValue = integerPart + ' 1/4';
} else if(checkValue == 3) {
// 33
newValue = integerPart + ' 1/3';
} else if(checkValue == 5) {
// 50
newValue = integerPart + ' 1/2';
} else if(checkValue == 6) {
// 66
newValue = integerPart + ' 2/3';
} else if(checkValue == 7) {
// 75
newValue = integerPart + ' 3/4';
}
if(integerPart == 0) newValue = newValue.slice(2, newValue.length);
}
currentLine = currentLine.replace(strToReplace, newValue);
$(this).text(currentLine);
});
}
Unfortunately, javascript regular expressions don't support negative lookbehinds, so you will get false positives on your fraction numbers when you are looking for just numbers. There's no way to say something like...
"/(?<!\/)([0-9])/"
...in javascript, so you will end up picking up some of the digits from the fraction.
You have to fake out the results with something like this:
Assuming your text is terminated with \n just for testing purposes:
var t = "1 1/2 oz. white rum (fractionsRegex)\n1/2 lime, cut in 4 wedges (fractionsRegex)\n10 mint leaves, fresh (numbersRegex)\n2 tbsp. white sugar (numbersRegex)\n1 cup ice cubes (numbersRegex)\n1/2 cup club soda (fractionsRegex)";
var ary = t.split("\n");
for (var i = 0; i < ary.length; i++) {
var fractionsRegex = ary[i].match(/((\d+)\/(\d+))/g);
var lineHiddenFractions = ary[i] != null ? ary[i].replace(/([0-9]{1,})([\/]{1})([0-9]{1,})/g, "") : "";
var numbersRegex = lineHiddenFractions.match(/([0-9]+(?:\.[0-9]*)?)/g);
if (fractionsRegex !== null && fractionsRegex.length > 0) {
// We have a fraction for this line.
for (var j = 0; j < fractionsRegex.length; j++) {
alert("Fraction on line " + i + ": " + fractionsRegex[j]);
}
}
if (numbersRegex !== null && numbersRegex.length > 0) {
// We have a number for this line.
for (var k = 0; k < numbersRegex.length; k++) {
alert("Number on line " + i + ": " + numbersRegex[k]);
}
}
}
I think this method offers you the most flexibility for what you want to do. For each line, you will get an array of all of your fractions and an array of all of your numbers. You can place booleans to check if the line has both numbers and fractions or just one or the other. If you need to perform calculations, you can create formulas from the arrays of fractions and numbers from each line.
to calculate
function measure(string){
var match = string.match(/^\d+(\s*\d*(\/+\d+))*/);
if(match){
match = match[0].split(" ");
var m = 0;
while(match.length){
m += eval(match.shift());
}
return m;
}
return 0;
}
or to get the values separately
function get(string){
var match = string.match(/^\d+(\s*\d*(\/+\d+))*/);
if(match){
match = match[0].split(" ");
var m = 0;
while(match.length){
m += eval(match.shift());
}
return {integer:Math.floor(m), fraction:m-Math.floor(m)};
}
return {integer:0, fraction:0};
}
or to replace integer part and fraction part seperately
function replaceInteger(string, newInt){
return string.replace(/^\d+\s+/, function(m, n){
return newInt + " ";
});
}
function replaceFraction(string, newFract){
return string.replace(/^\d+\/+\d+\s+/, function(m, n){
return newFract + " ";
});
}
replaceInteger("10 mint leaves, fresh", "100");
replaceFraction("1/2 lime leaves, fresh", "1/3");
I think this approach will do what you need. Just call getQuantity, it will return an object which may or may not contain properties number and fraction. Then once you get the result, you can perform logic to determine what to do with it.
function getQuantity(recipe){
var regex = /^(([1-9]+\d*\s)?((\d+)\/(\d+)\s)?).*$/g;
var results = regex.exec(recipe);
if(results[2] && results[5]){
return {number: Number(results[2]), fraction: Number(results[4]) / Number(results[5])};
} if(results[5]){
return {fraction: Number(results[4]) / Number(results[5])};
} else{
return {number: Number(results[2])};
}
}
getQuantity("1 1/2 oz. white rum"); // {number: 1, fraction: 0.5}
getQuantity("1/2 lime, cut in 4 wedges"); // {fraction: 0.5}
getQuantity("10 mint leaves, fresh"); // {number: 10}
getQuantity("2 tbsp. white sugar"); // {number: 2}
getQuantity("1 cup ice cubes"); // {number: 1}
getQuantity("1/2 cup club soda"); // {fraction: 0.5}

Categories