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!
I was given a quiz and I had gotten the answer wrong and It's been bugging me ever since so I thought I'd ask for your thoughts
I needed to optimise the following function
function sumOfEvenNumbers(n) {
var sum = 0;
for(let i = 2; i < n;i++){
if(i % 2 == 0) sum += i;
}
return sum;
}
console.log(sumOfEvenNumbers(5));
I came up with
function sumOfEvenNumbers(n) {
var sum = 0;
while(--n >= 2) sum += n % 2 == 0? n : 0
return sum;
}
console.log(sumOfEvenNumbers(5));
What other ways were there?
It's a bit of a math question. The sum appears to be the sum of an arithmitic sequence with a common difference of 2. The sum is:
sum = N * (last + first) / 2;
where N is the number of the numbers in the sequence, last is the last number of those numbers, and first is the first.
Translated to javascript as:
function sumOfEvenNumbers(n) {
return Math.floor(n / 2) * (n - n % 2 + 2) / 2;
}
Because the number of even numbers between 2 and n is Math.floor(n / 2) and the last even number is n - n % 2 (7 would be 7 - 7 % 2 === 6 and 8 would be 8 - 8 % 2 === 8). and the first is 2.
Sum of n numbers:
var sum = (n * (n+1)) / 2;
Sum of n even numbers:
var m = Math.floor(n/2);
var sum = 2 * (m * (m+1) /2);
You can compute these sums using an arithmetic sum formula in constant time:
// Return sum of positive even numbers < n:
function sumOfEvenNumbers(n) {
n = (n - 1) >> 1;
return n * (n + 1);
}
// Example:
console.log(sumOfEvenNumbers(5));
Above computation avoids modulo and division operators which consume more CPU cycles than multiplication, addition and bit-shifting. Pay attention to the limited range of the bit-shifting operator >> though.
See e.g. http://oeis.org/A002378 for this and other formulas leading to the same result.
First thing is to eliminate the test in the loop:
function sumOfEvenNumbers(n) {
var sum = 0;
var halfN= Math.floor(n/2);
for(let i = 1; i < n/2;i++) {
sum += i;
}
return sum * 2;
}
Then we can observe that is just calculating the sum of all the integers less than a limit - and there is a formula for that (but actually formula is for less-equal a limit).
function sumOfEvenNumbers(n) {
var halfNm1= Math.floor(n/2)-1;
var sum = halfNm1 * (halfNm1+1) / 2;
return sum * 2;
}
And then eliminate the division and multiplication and the unnecessary addition and subtraction:
function sumOfEvenNumbers(n) {
var halfN= Math.floor(n/2);
return (halfN-1) * halfN;
}
Your solution computes in linear (O(N)) time.
If you use a mathematical solution, you can compute it in O(1) time:
function sum(n) {
let half = Math.ceil(n/2)
return half * (half + 1)
}
Because the question is tagged ecmascript-6 :)
const sumEven = x => [...Array(x + 1).keys()].reduce((a, b) => b % 2 === 0 ? a + b : a, 0);
// set max number
console.log(sumEven(10));
Suppose I have a value of 15.7784514, I want to display it 15.77 with no rounding.
var num = parseFloat(15.7784514);
document.write(num.toFixed(1)+"<br />");
document.write(num.toFixed(2)+"<br />");
document.write(num.toFixed(3)+"<br />");
document.write(num.toFixed(10));
Results in -
15.8
15.78
15.778
15.7784514000
How do I display 15.77?
Convert the number into a string, match the number up to the second decimal place:
function calc(theform) {
var num = theform.original.value, rounded = theform.rounded
var with2Decimals = num.toString().match(/^-?\d+(?:\.\d{0,2})?/)[0]
rounded.value = with2Decimals
}
<form onsubmit="return calc(this)">
Original number: <input name="original" type="text" onkeyup="calc(form)" onchange="calc(form)" />
<br />"Rounded" number: <input name="rounded" type="text" placeholder="readonly" readonly>
</form>
The toFixed method fails in some cases unlike toString, so be very careful with it.
Update 5 Nov 2016
New answer, always accurate
function toFixed(num, fixed) {
var re = new RegExp('^-?\\d+(?:\.\\d{0,' + (fixed || -1) + '})?');
return num.toString().match(re)[0];
}
As floating point math in javascript will always have edge cases, the previous solution will be accurate most of the time which is not good enough.
There are some solutions to this like num.toPrecision, BigDecimal.js, and accounting.js.
Yet, I believe that merely parsing the string will be the simplest and always accurate.
Basing the update on the well written regex from the accepted answer by #Gumbo, this new toFixed function will always work as expected.
Old answer, not always accurate.
Roll your own toFixed function:
function toFixed(num, fixed) {
fixed = fixed || 0;
fixed = Math.pow(10, fixed);
return Math.floor(num * fixed) / fixed;
}
Another single-line solution :
number = Math.trunc(number*100)/100
I used 100 because you want to truncate to the second digit, but a more flexible solution would be :
number = Math.trunc(number*Math.pow(10, digits))/Math.pow(10, digits)
where digits is the amount of decimal digits to keep.
See Math.trunc specs for details and browser compatibility.
I opted to write this instead to manually remove the remainder with strings so I don't have to deal with the math issues that come with numbers:
num = num.toString(); //If it's not already a String
num = num.slice(0, (num.indexOf("."))+3); //With 3 exposing the hundredths place
Number(num); //If you need it back as a Number
This will give you "15.77" with num = 15.7784514;
Update (Jan 2021)
Depending on its range, a number in javascript may be shown in scientific notation. For example, if you type 0.0000001 in the console, you may see it as 1e-7, whereas 0.000001 appears unchanged (0.000001).
If your application works on a range of numbers for which scientific notation is not involved, you can just ignore this update and use the original answer below.
This update is about adding a function that checks if the number is in scientific format and, if so, converts it into decimal format. Here I'm proposing this one, but you can use any other function that achieves the same goal, according to your application's needs:
function toFixed(x) {
if (Math.abs(x) < 1.0) {
let e = parseInt(x.toString().split('e-')[1]);
if (e) {
x *= Math.pow(10,e-1);
x = '0.' + (new Array(e)).join('0') + x.toString().substring(2);
}
} else {
let e = parseInt(x.toString().split('+')[1]);
if (e > 20) {
e -= 20;
x /= Math.pow(10,e);
x += (new Array(e+1)).join('0');
}
}
return x;
}
Now just apply that function to the parameter (that's the only change with respect to the original answer):
function toFixedTrunc(x, n) {
x = toFixed(x)
// From here on the code is the same than the original answer
const v = (typeof x === 'string' ? x : x.toString()).split('.');
if (n <= 0) return v[0];
let f = v[1] || '';
if (f.length > n) return `${v[0]}.${f.substr(0,n)}`;
while (f.length < n) f += '0';
return `${v[0]}.${f}`
}
This updated version addresses also a case mentioned in a comment:
toFixedTrunc(0.000000199, 2) => "0.00"
Again, choose what fits your application needs at best.
Original answer (October 2017)
General solution to truncate (no rounding) a number to the n-th decimal digit and convert it to a string with exactly n decimal digits, for any n≥0.
function toFixedTrunc(x, n) {
const v = (typeof x === 'string' ? x : x.toString()).split('.');
if (n <= 0) return v[0];
let f = v[1] || '';
if (f.length > n) return `${v[0]}.${f.substr(0,n)}`;
while (f.length < n) f += '0';
return `${v[0]}.${f}`
}
where x can be either a number (which gets converted into a string) or a string.
Here are some tests for n=2 (including the one requested by OP):
0 => 0.00
0.01 => 0.01
0.5839 => 0.58
0.999 => 0.99
1.01 => 1.01
2 => 2.00
2.551 => 2.55
2.99999 => 2.99
4.27 => 4.27
15.7784514 => 15.77
123.5999 => 123.59
And for some other values of n:
15.001097 => 15.0010 (n=4)
0.000003298 => 0.0000032 (n=7)
0.000003298257899 => 0.000003298257 (n=12)
parseInt is faster then Math.floor
function floorFigure(figure, decimals){
if (!decimals) decimals = 2;
var d = Math.pow(10,decimals);
return (parseInt(figure*d)/d).toFixed(decimals);
};
floorFigure(123.5999) => "123.59"
floorFigure(123.5999, 3) => "123.599"
num = 19.66752
f = num.toFixed(3).slice(0,-1)
alert(f)
This will return 19.66
Simple do this
number = parseInt(number * 100)/100;
Just truncate the digits:
function truncDigits(inputNumber, digits) {
const fact = 10 ** digits;
return Math.floor(inputNumber * fact) / fact;
}
This is not a safe alternative, as many others commented examples with numbers that turn into exponential notation, that scenery is not covered by this function
// typescript
// function formatLimitDecimals(value: number, decimals: number): number {
function formatLimitDecimals(value, decimals) {
const stringValue = value.toString();
if(stringValue.includes('e')) {
// TODO: remove exponential notation
throw 'invald number';
} else {
const [integerPart, decimalPart] = stringValue.split('.');
if(decimalPart) {
return +[integerPart, decimalPart.slice(0, decimals)].join('.')
} else {
return integerPart;
}
}
}
console.log(formatLimitDecimals(4.156, 2)); // 4.15
console.log(formatLimitDecimals(4.156, 8)); // 4.156
console.log(formatLimitDecimals(4.156, 0)); // 4
console.log(formatLimitDecimals(0, 4)); // 0
// not covered
console.log(formatLimitDecimals(0.000000199, 2)); // 0.00
These solutions do work, but to me seem unnecessarily complicated. I personally like to use the modulus operator to obtain the remainder of a division operation, and remove that. Assuming that num = 15.7784514:
num-=num%.01;
This is equivalent to saying num = num - (num % .01).
I fixed using following simple way-
var num = 15.7784514;
Math.floor(num*100)/100;
Results will be 15.77
My version for positive numbers:
function toFixed_norounding(n,p)
{
var result = n.toFixed(p);
return result <= n ? result: (result - Math.pow(0.1,p)).toFixed(p);
}
Fast, pretty, obvious. (version for positive numbers)
The answers here didn't help me, it kept rounding up or giving me the wrong decimal.
my solution converts your decimal to a string, extracts the characters and then returns the whole thing as a number.
function Dec2(num) {
num = String(num);
if(num.indexOf('.') !== -1) {
var numarr = num.split(".");
if (numarr.length == 1) {
return Number(num);
}
else {
return Number(numarr[0]+"."+numarr[1].charAt(0)+numarr[1].charAt(1));
}
}
else {
return Number(num);
}
}
Dec2(99); // 99
Dec2(99.9999999); // 99.99
Dec2(99.35154); // 99.35
Dec2(99.8); // 99.8
Dec2(10265.985475); // 10265.98
The following code works very good for me:
num.toString().match(/.\*\\..{0,2}|.\*/)[0];
This worked well for me. I hope it will fix your issues too.
function toFixedNumber(number) {
const spitedValues = String(number.toLocaleString()).split('.');
let decimalValue = spitedValues.length > 1 ? spitedValues[1] : '';
decimalValue = decimalValue.concat('00').substr(0,2);
return '$'+spitedValues[0] + '.' + decimalValue;
}
// 5.56789 ----> $5.56
// 0.342 ----> $0.34
// -10.3484534 ----> $-10.34
// 600 ----> $600.00
function convertNumber(){
var result = toFixedNumber(document.getElementById("valueText").value);
document.getElementById("resultText").value = result;
}
function toFixedNumber(number) {
const spitedValues = String(number.toLocaleString()).split('.');
let decimalValue = spitedValues.length > 1 ? spitedValues[1] : '';
decimalValue = decimalValue.concat('00').substr(0,2);
return '$'+spitedValues[0] + '.' + decimalValue;
}
<div>
<input type="text" id="valueText" placeholder="Input value here..">
<br>
<button onclick="convertNumber()" >Convert</button>
<br><hr>
<input type="text" id="resultText" placeholder="result" readonly="true">
</div>
An Easy way to do it is the next but is necessary ensure that the amount parameter is given as a string.
function truncate(amountAsString, decimals = 2){
var dotIndex = amountAsString.indexOf('.');
var toTruncate = dotIndex !== -1 && ( amountAsString.length > dotIndex + decimals + 1);
var approach = Math.pow(10, decimals);
var amountToTruncate = toTruncate ? amountAsString.slice(0, dotIndex + decimals +1) : amountAsString;
return toTruncate
? Math.floor(parseFloat(amountToTruncate) * approach ) / approach
: parseFloat(amountAsString);
}
console.log(truncate("7.99999")); //OUTPUT ==> 7.99
console.log(truncate("7.99999", 3)); //OUTPUT ==> 7.999
console.log(truncate("12.799999999999999")); //OUTPUT ==> 7.99
Here you are. An answer that shows yet another way to solve the problem:
// For the sake of simplicity, here is a complete function:
function truncate(numToBeTruncated, numOfDecimals) {
var theNumber = numToBeTruncated.toString();
var pointIndex = theNumber.indexOf('.');
return +(theNumber.slice(0, pointIndex > -1 ? ++numOfDecimals + pointIndex : undefined));
}
Note the use of + before the final expression. That is to convert our truncated, sliced string back to number type.
Hope it helps!
truncate without zeroes
function toTrunc(value,n){
return Math.floor(value*Math.pow(10,n))/(Math.pow(10,n));
}
or
function toTrunc(value,n){
x=(value.toString()+".0").split(".");
return parseFloat(x[0]+"."+x[1].substr(0,n));
}
test:
toTrunc(17.4532,2) //17.45
toTrunc(177.4532,1) //177.4
toTrunc(1.4532,1) //1.4
toTrunc(.4,2) //0.4
truncate with zeroes
function toTruncFixed(value,n){
return toTrunc(value,n).toFixed(n);
}
test:
toTrunc(17.4532,2) //17.45
toTrunc(177.4532,1) //177.4
toTrunc(1.4532,1) //1.4
toTrunc(.4,2) //0.40
If you exactly wanted to truncate to 2 digits of precision, you can go with a simple logic:
function myFunction(number) {
var roundedNumber = number.toFixed(2);
if (roundedNumber > number)
{
roundedNumber = roundedNumber - 0.01;
}
return roundedNumber;
}
I used (num-0.05).toFixed(1) to get the second decimal floored.
It's more reliable to get two floating points without rounding.
Reference Answer
var number = 10.5859;
var fixed2FloatPoints = parseInt(number * 100) / 100;
console.log(fixed2FloatPoints);
Thank You !
My solution in typescript (can easily be ported to JS):
/**
* Returns the price with correct precision as a string
*
* #param price The price in decimal to be formatted.
* #param decimalPlaces The number of decimal places to use
* #return string The price in Decimal formatting.
*/
type toDecimal = (price: number, decimalPlaces?: number) => string;
const toDecimalOdds: toDecimal = (
price: number,
decimalPlaces: number = 2,
): string => {
const priceString: string = price.toString();
const pointIndex: number = priceString.indexOf('.');
// Return the integer part if decimalPlaces is 0
if (decimalPlaces === 0) {
return priceString.substr(0, pointIndex);
}
// Return value with 0s appended after decimal if the price is an integer
if (pointIndex === -1) {
const padZeroString: string = '0'.repeat(decimalPlaces);
return `${priceString}.${padZeroString}`;
}
// If numbers after decimal are less than decimalPlaces, append with 0s
const padZeroLen: number = priceString.length - pointIndex - 1;
if (padZeroLen > 0 && padZeroLen < decimalPlaces) {
const padZeroString: string = '0'.repeat(padZeroLen);
return `${priceString}${padZeroString}`;
}
return priceString.substr(0, pointIndex + decimalPlaces + 1);
};
Test cases:
expect(filters.toDecimalOdds(3.14159)).toBe('3.14');
expect(filters.toDecimalOdds(3.14159, 2)).toBe('3.14');
expect(filters.toDecimalOdds(3.14159, 0)).toBe('3');
expect(filters.toDecimalOdds(3.14159, 10)).toBe('3.1415900000');
expect(filters.toDecimalOdds(8.2)).toBe('8.20');
Any improvements?
Another solution, that truncates and round:
function round (number, decimals, truncate) {
if (truncate) {
number = number.toFixed(decimals + 1);
return parseFloat(number.slice(0, -1));
}
var n = Math.pow(10.0, decimals);
return Math.round(number * n) / n;
};
function limitDecimalsWithoutRounding(val, decimals){
let parts = val.toString().split(".");
return parseFloat(parts[0] + "." + parts[1].substring(0, decimals));
}
var num = parseFloat(15.7784514);
var new_num = limitDecimalsWithoutRounding(num, 2);
Roll your own toFixed function: for positive values Math.floor works fine.
function toFixed(num, fixed) {
fixed = fixed || 0;
fixed = Math.pow(10, fixed);
return Math.floor(num * fixed) / fixed;
}
For negative values Math.floor is round of the values. So you can use Math.ceil instead.
Example,
Math.ceil(-15.778665 * 10000) / 10000 = -15.7786
Math.floor(-15.778665 * 10000) / 10000 = -15.7787 // wrong.
Gumbo's second solution, with the regular expression, does work but is slow because of the regular expression. Gumbo's first solution fails in certain situations due to imprecision in floating points numbers. See the JSFiddle for a demonstration and a benchmark. The second solution takes about 1636 nanoseconds per call on my current system, Intel Core i5-2500 CPU at 3.30 GHz.
The solution I've written involves adding a small compensation to take care of floating point imprecision. It is basically instantaneous, i.e. on the order of nanoseconds. I clocked 2 nanoseconds per call but the JavaScript timers are not very precise or granular. Here is the JS Fiddle and the code.
function toFixedWithoutRounding (value, precision)
{
var factorError = Math.pow(10, 14);
var factorTruncate = Math.pow(10, 14 - precision);
var factorDecimal = Math.pow(10, precision);
return Math.floor(Math.floor(value * factorError + 1) / factorTruncate) / factorDecimal;
}
var values = [1.1299999999, 1.13, 1.139999999, 1.14, 1.14000000001, 1.13 * 100];
for (var i = 0; i < values.length; i++)
{
var value = values[i];
console.log(value + " --> " + toFixedWithoutRounding(value, 2));
}
for (var i = 0; i < values.length; i++)
{
var value = values[i];
console.log(value + " --> " + toFixedWithoutRounding(value, 4));
}
console.log("type of result is " + typeof toFixedWithoutRounding(1.13 * 100 / 100, 2));
// Benchmark
var value = 1.13 * 100;
var startTime = new Date();
var numRun = 1000000;
var nanosecondsPerMilliseconds = 1000000;
for (var run = 0; run < numRun; run++)
toFixedWithoutRounding(value, 2);
var endTime = new Date();
var timeDiffNs = nanosecondsPerMilliseconds * (endTime - startTime);
var timePerCallNs = timeDiffNs / numRun;
console.log("Time per call (nanoseconds): " + timePerCallNs);
Building on David D's answer:
function NumberFormat(num,n) {
var num = (arguments[0] != null) ? arguments[0] : 0;
var n = (arguments[1] != null) ? arguments[1] : 2;
if(num > 0){
num = String(num);
if(num.indexOf('.') !== -1) {
var numarr = num.split(".");
if (numarr.length > 1) {
if(n > 0){
var temp = numarr[0] + ".";
for(var i = 0; i < n; i++){
if(i < numarr[1].length){
temp += numarr[1].charAt(i);
}
}
num = Number(temp);
}
}
}
}
return Number(num);
}
console.log('NumberFormat(123.85,2)',NumberFormat(123.85,2));
console.log('NumberFormat(123.851,2)',NumberFormat(123.851,2));
console.log('NumberFormat(0.85,2)',NumberFormat(0.85,2));
console.log('NumberFormat(0.851,2)',NumberFormat(0.851,2));
console.log('NumberFormat(0.85156,2)',NumberFormat(0.85156,2));
console.log('NumberFormat(0.85156,4)',NumberFormat(0.85156,4));
console.log('NumberFormat(0.85156,8)',NumberFormat(0.85156,8));
console.log('NumberFormat(".85156",2)',NumberFormat(".85156",2));
console.log('NumberFormat("0.85156",2)',NumberFormat("0.85156",2));
console.log('NumberFormat("1005.85156",2)',NumberFormat("1005.85156",2));
console.log('NumberFormat("0",2)',NumberFormat("0",2));
console.log('NumberFormat("",2)',NumberFormat("",2));
console.log('NumberFormat(85156,8)',NumberFormat(85156,8));
console.log('NumberFormat("85156",2)',NumberFormat("85156",2));
console.log('NumberFormat("85156.",2)',NumberFormat("85156.",2));
// NumberFormat(123.85,2) 123.85
// NumberFormat(123.851,2) 123.85
// NumberFormat(0.85,2) 0.85
// NumberFormat(0.851,2) 0.85
// NumberFormat(0.85156,2) 0.85
// NumberFormat(0.85156,4) 0.8515
// NumberFormat(0.85156,8) 0.85156
// NumberFormat(".85156",2) 0.85
// NumberFormat("0.85156",2) 0.85
// NumberFormat("1005.85156",2) 1005.85
// NumberFormat("0",2) 0
// NumberFormat("",2) 0
// NumberFormat(85156,8) 85156
// NumberFormat("85156",2) 85156
// NumberFormat("85156.",2) 85156
Already there are some suitable answer with regular expression and arithmetic calculation, you can also try this
function myFunction() {
var str = 12.234556;
str = str.toString().split('.');
var res = str[1].slice(0, 2);
document.getElementById("demo").innerHTML = str[0]+'.'+res;
}
// output: 12.23
Here is what is did it with string
export function withoutRange(number) {
const str = String(number);
const dotPosition = str.indexOf('.');
if (dotPosition > 0) {
const length = str.substring().length;
const end = length > 3 ? 3 : length;
return str.substring(0, dotPosition + end);
}
return str;
}
How can I generate random whole numbers between two specified variables in JavaScript, e.g. x = 4 and y = 8 would output any of 4, 5, 6, 7, 8?
There are some examples on the Mozilla Developer Network page:
/**
* Returns a random number between min (inclusive) and max (exclusive)
*/
function getRandomArbitrary(min, max) {
return Math.random() * (max - min) + min;
}
/**
* Returns a random integer between min (inclusive) and max (inclusive).
* The value is no lower than min (or the next integer greater than min
* if min isn't an integer) and no greater than max (or the next integer
* lower than max if max isn't an integer).
* Using Math.round() will give you a non-uniform distribution!
*/
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
Here's the logic behind it. It's a simple rule of three:
Math.random() returns a Number between 0 (inclusive) and 1 (exclusive). So we have an interval like this:
[0 .................................... 1)
Now, we'd like a number between min (inclusive) and max (exclusive):
[0 .................................... 1)
[min .................................. max)
We can use the Math.random to get the correspondent in the [min, max) interval. But, first we should factor a little bit the problem by subtracting min from the second interval:
[0 .................................... 1)
[min - min ............................ max - min)
This gives:
[0 .................................... 1)
[0 .................................... max - min)
We may now apply Math.random and then calculate the correspondent. Let's choose a random number:
Math.random()
|
[0 .................................... 1)
[0 .................................... max - min)
|
x (what we need)
So, in order to find x, we would do:
x = Math.random() * (max - min);
Don't forget to add min back, so that we get a number in the [min, max) interval:
x = Math.random() * (max - min) + min;
That was the first function from MDN. The second one, returns an integer between min and max, both inclusive.
Now for getting integers, you could use round, ceil or floor.
You could use Math.round(Math.random() * (max - min)) + min, this however gives a non-even distribution. Both, min and max only have approximately half the chance to roll:
min...min+0.5...min+1...min+1.5 ... max-0.5....max
└───┬───┘└────────┬───────┘└───── ... ─────┘└───┬──┘ ← Math.round()
min min+1 max
With max excluded from the interval, it has an even less chance to roll than min.
With Math.floor(Math.random() * (max - min +1)) + min you have a perfectly even distribution.
min... min+1... ... max-1... max.... (max+1 is excluded from interval)
└───┬───┘└───┬───┘└─── ... ┘└───┬───┘└───┬───┘ ← Math.floor()
min min+1 max-1 max
You can't use ceil() and -1 in that equation because max now had a slightly less chance to roll, but you can roll the (unwanted) min-1 result too.
var randomnumber = Math.floor(Math.random() * (maximum - minimum + 1)) + minimum;
Math.random()
Returns an integer random number between min (included) and max (included):
function randomInteger(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
Or any random number between min (included) and max (not included):
function randomNumber(min, max) {
return Math.random() * (max - min) + min;
}
Useful examples (integers):
// 0 -> 10
Math.floor(Math.random() * 11);
// 1 -> 10
Math.floor(Math.random() * 10) + 1;
// 5 -> 20
Math.floor(Math.random() * 16) + 5;
// -10 -> (-2)
Math.floor(Math.random() * 9) - 10;
** And always nice to be reminded (Mozilla):
Math.random() does not provide cryptographically secure random
numbers. Do not use them for anything related to security. Use the Web
Crypto API instead, and more precisely the
window.crypto.getRandomValues() method.
Use:
function getRandomizer(bottom, top) {
return function() {
return Math.floor( Math.random() * ( 1 + top - bottom ) ) + bottom;
}
}
Usage:
var rollDie = getRandomizer( 1, 6 );
var results = ""
for ( var i = 0; i<1000; i++ ) {
results += rollDie() + " "; // Make a string filled with 1000 random numbers in the range 1-6.
}
Breakdown:
We are returning a function (borrowing from functional programming) that when called, will return a random integer between the the values bottom and top, inclusive. We say 'inclusive' because we want to include both bottom and top in the range of numbers that can be returned. This way, getRandomizer( 1, 6 ) will return either 1, 2, 3, 4, 5, or 6.
('bottom' is the lower number, and 'top' is the greater number)
Math.random() * ( 1 + top - bottom )
Math.random() returns a random double between 0 and 1, and if we multiply it by one plus the difference between top and bottom, we'll get a double somewhere between 0 and 1+b-a.
Math.floor( Math.random() * ( 1 + top - bottom ) )
Math.floor rounds the number down to the nearest integer. So we now have all the integers between 0 and top-bottom. The 1 looks confusing, but it needs to be there because we are always rounding down, so the top number will never actually be reached without it. The random decimal we generate needs to be in the range 0 to (1+top-bottom) so we can round down and get an integer in the range 0 to top-bottom:
Math.floor( Math.random() * ( 1 + top - bottom ) ) + bottom
The code in the previous example gave us an integer in the range 0 and top-bottom, so all we need to do now is add bottom to that result to get an integer in the range bottom and top inclusive. :D
NOTE: If you pass in a non-integer value or the greater number first you'll get undesirable behavior, but unless anyone requests it I am not going to delve into the argument checking code as it’s rather far from the intent of the original question.
All these solutions are using way too much firepower. You only need to call one function: Math.random();
Math.random() * max | 0;
This returns a random integer between 0 (inclusive) and max (non-inclusive).
Return a random number between 1 and 10:
Math.floor((Math.random()*10) + 1);
Return a random number between 1 and 100:
Math.floor((Math.random()*100) + 1)
function randomRange(min, max) {
return ~~(Math.random() * (max - min + 1)) + min
}
Alternative if you are using Underscore.js you can use
_.random(min, max)
If you need a variable between 0 and max, you can use:
Math.floor(Math.random() * max);
The other answers don't account for the perfectly reasonable parameters of 0 and 1. Instead you should use the round instead of ceil or floor:
function randomNumber(minimum, maximum){
return Math.round( Math.random() * (maximum - minimum) + minimum);
}
console.log(randomNumber(0,1)); # 0 1 1 0 1 0
console.log(randomNumber(5,6)); # 5 6 6 5 5 6
console.log(randomNumber(3,-1)); # 1 3 1 -1 -1 -1
Cryptographically strong
To get a cryptographically strong random integer number in the range [x,y], try:
let cs = (x,y) => x + (y - x + 1)*crypto.getRandomValues(new Uint32Array(1))[0]/2**32 | 0
console.log(cs(4, 8))
Here's what I use to generate random numbers.
function random(min,max) {
return Math.floor((Math.random())*(max-min+1))+min;
}
Math.random() returns a number between 0 (inclusive) and 1 (exclusive). We multiply this number by the range (max-min). This results in a number between 0 (inclusive), and the range.
For example, take random(2,5). We multiply the random number 0≤x<1 by the range (5-2=3), so we now have a number, x where 0≤x<3.
In order to force the function to treat both the max and min as inclusive, we add 1 to our range calculation: Math.random()*(max-min+1). Now, we multiply the random number by the (5-2+1=4), resulting in an number, x, such that 0≤x<4. If we floor this calculation, we get an integer: 0≤x≤3, with an equal likelihood of each result (1/4).
Finally, we need to convert this into an integer between the requested values. Since we already have an integer between 0 and the (max-min), we can simply map the value into the correct range by adding the minimum value. In our example, we add 2 our integer between 0 and 3, resulting in an integer between 2 and 5.
Use this function to get random numbers in a given range:
function rnd(min, max) {
return Math.floor(Math.random()*(max - min + 1) + min);
}
Here is the Microsoft .NET Implementation of the Random class in JavaScript—
var Random = (function () {
function Random(Seed) {
if (!Seed) {
Seed = this.milliseconds();
}
this.SeedArray = [];
for (var i = 0; i < 56; i++)
this.SeedArray.push(0);
var num = (Seed == -2147483648) ? 2147483647 : Math.abs(Seed);
var num2 = 161803398 - num;
this.SeedArray[55] = num2;
var num3 = 1;
for (var i_1 = 1; i_1 < 55; i_1++) {
var num4 = 21 * i_1 % 55;
this.SeedArray[num4] = num3;
num3 = num2 - num3;
if (num3 < 0) {
num3 += 2147483647;
}
num2 = this.SeedArray[num4];
}
for (var j = 1; j < 5; j++) {
for (var k = 1; k < 56; k++) {
this.SeedArray[k] -= this.SeedArray[1 + (k + 30) % 55];
if (this.SeedArray[k] < 0) {
this.SeedArray[k] += 2147483647;
}
}
}
this.inext = 0;
this.inextp = 21;
Seed = 1;
}
Random.prototype.milliseconds = function () {
var str = new Date().valueOf().toString();
return parseInt(str.substr(str.length - 6));
};
Random.prototype.InternalSample = function () {
var num = this.inext;
var num2 = this.inextp;
if (++num >= 56) {
num = 1;
}
if (++num2 >= 56) {
num2 = 1;
}
var num3 = this.SeedArray[num] - this.SeedArray[num2];
if (num3 == 2147483647) {
num3--;
}
if (num3 < 0) {
num3 += 2147483647;
}
this.SeedArray[num] = num3;
this.inext = num;
this.inextp = num2;
return num3;
};
Random.prototype.Sample = function () {
return this.InternalSample() * 4.6566128752457969E-10;
};
Random.prototype.GetSampleForLargeRange = function () {
var num = this.InternalSample();
var flag = this.InternalSample() % 2 == 0;
if (flag) {
num = -num;
}
var num2 = num;
num2 += 2147483646.0;
return num2 / 4294967293.0;
};
Random.prototype.Next = function (minValue, maxValue) {
if (!minValue && !maxValue)
return this.InternalSample();
var num = maxValue - minValue;
if (num <= 2147483647) {
return parseInt((this.Sample() * num + minValue).toFixed(0));
}
return this.GetSampleForLargeRange() * num + minValue;
};
Random.prototype.NextDouble = function () {
return this.Sample();
};
Random.prototype.NextBytes = function (buffer) {
for (var i = 0; i < buffer.length; i++) {
buffer[i] = this.InternalSample() % 256;
}
};
return Random;
}());
Use:
var r = new Random();
var nextInt = r.Next(1, 100); // Returns an integer between range
var nextDbl = r.NextDouble(); // Returns a random decimal
I wanted to explain using an example:
Function to generate random whole numbers in JavaScript within a range of 5 to 25
General Overview:
(i) First convert it to the range - starting from 0.
(ii) Then convert it to your desired range ( which then will be very
easy to complete).
So basically, if you want to generate random whole numbers from 5 to 25 then:
First step: Converting it to range - starting from 0
Subtract "lower/minimum number" from both "max" and "min". i.e
(5-5) - (25-5)
So the range will be:
0-20 ...right?
Step two
Now if you want both numbers inclusive in range - i.e "both 0 and 20", the equation will be:
Mathematical equation: Math.floor((Math.random() * 21))
General equation: Math.floor((Math.random() * (max-min +1)))
Now if we add subtracted/minimum number (i.e., 5) to the range - then automatically we can get range from 0 to 20 => 5 to 25
Step three
Now add the difference you subtracted in equation (i.e., 5) and add "Math.floor" to the whole equation:
Mathematical equation: Math.floor((Math.random() * 21) + 5)
General equation: Math.floor((Math.random() * (max-min +1)) + min)
So finally the function will be:
function randomRange(min, max) {
return Math.floor((Math.random() * (max - min + 1)) + min);
}
After generating a random number using a computer program, it is still considered as a random number if the picked number is a part or the full one of the initial one. But if it was changed, then mathematicians do not accept it as a random number and they can call it a biased number.
But if you are developing a program for a simple task, this will not be a case to consider. But if you are developing a program to generate a random number for a valuable stuff such as lottery program, or gambling game, then your program will be rejected by the management if you are not consider about the above case.
So for those kind of people, here is my suggestion:
Generate a random number using Math.random() (say this n):
Now for [0,10) ==> n*10 (i.e. one digit) and for[10,100) ==> n*100 (i.e., two digits) and so on. Here square bracket indicates that the boundary is inclusive and a round bracket indicates the boundary is exclusive.
Then remove the rest after the decimal point. (i.e., get the floor) - using Math.floor(). This can be done.
If you know how to read the random number table to pick a random number, you know the above process (multiplying by 1, 10, 100 and so on) does not violate the one that I was mentioned at the beginning (because it changes only the place of the decimal point).
Study the following example and develop it to your needs.
If you need a sample [0,9] then the floor of n10 is your answer and if you need [0,99] then the floor of n100 is your answer and so on.
Now let’s enter into your role:
You've asked for numbers in a specific range. (In this case you are biased among that range. By taking a number from [1,6] by roll a die, then you are biased into [1,6], but still it is a random number if and only if the die is unbiased.)
So consider your range ==> [78, 247]
number of elements of the range = 247 - 78 + 1 = 170; (since both the boundaries are inclusive).
/* Method 1: */
var i = 78, j = 247, k = 170, a = [], b = [], c, d, e, f, l = 0;
for(; i <= j; i++){ a.push(i); }
while(l < 170){
c = Math.random()*100; c = Math.floor(c);
d = Math.random()*100; d = Math.floor(d);
b.push(a[c]); e = c + d;
if((b.length != k) && (e < k)){ b.push(a[e]); }
l = b.length;
}
console.log('Method 1:');
console.log(b);
/* Method 2: */
var a, b, c, d = [], l = 0;
while(l < 170){
a = Math.random()*100; a = Math.floor(a);
b = Math.random()*100; b = Math.floor(b);
c = a + b;
if(c <= 247 || c >= 78){ d.push(c); }else{ d.push(a); }
l = d.length;
}
console.log('Method 2:');
console.log(d);
Note: In method one, first I created an array which contains numbers that you need and then randomly put them into another array.
In method two, generate numbers randomly and check those are in the range that you need. Then put it into an array. Here I generated two random numbers and used the total of them to maximize the speed of the program by minimizing the failure rate that obtaining a useful number. However, adding generated numbers will also give some biasedness. So I would recommend my first method to generate random numbers within a specific range.
In both methods, your console will show the result (press F12 in Chrome to open the console).
function getRandomInt(lower, upper)
{
//to create an even sample distribution
return Math.floor(lower + (Math.random() * (upper - lower + 1)));
//to produce an uneven sample distribution
//return Math.round(lower + (Math.random() * (upper - lower)));
//to exclude the max value from the possible values
//return Math.floor(lower + (Math.random() * (upper - lower)));
}
To test this function, and variations of this function, save the below HTML/JavaScript to a file and open with a browser. The code will produce a graph showing the distribution of one million function calls. The code will also record the edge cases, so if the the function produces a value greater than the max, or less than the min, you.will.know.about.it.
<html>
<head>
<script type="text/javascript">
function getRandomInt(lower, upper)
{
//to create an even sample distribution
return Math.floor(lower + (Math.random() * (upper - lower + 1)));
//to produce an uneven sample distribution
//return Math.round(lower + (Math.random() * (upper - lower)));
//to exclude the max value from the possible values
//return Math.floor(lower + (Math.random() * (upper - lower)));
}
var min = -5;
var max = 5;
var array = new Array();
for(var i = 0; i <= (max - min) + 2; i++) {
array.push(0);
}
for(var i = 0; i < 1000000; i++) {
var random = getRandomInt(min, max);
array[random - min + 1]++;
}
var maxSample = 0;
for(var i = 0; i < max - min; i++) {
maxSample = Math.max(maxSample, array[i]);
}
//create a bar graph to show the sample distribution
var maxHeight = 500;
for(var i = 0; i <= (max - min) + 2; i++) {
var sampleHeight = (array[i]/maxSample) * maxHeight;
document.write('<span style="display:inline-block;color:'+(sampleHeight == 0 ? 'black' : 'white')+';background-color:black;height:'+sampleHeight+'px"> [' + (i + min - 1) + ']: '+array[i]+'</span> ');
}
document.write('<hr/>');
</script>
</head>
<body>
</body>
</html>
For a random integer with a range, try:
function random(minimum, maximum) {
var bool = true;
while (bool) {
var number = (Math.floor(Math.random() * maximum + 1) + minimum);
if (number > 20) {
bool = true;
} else {
bool = false;
}
}
return number;
}
Here is a function that generates a random number between min and max, both inclusive.
const randomInt = (max, min) => Math.round(Math.random() * (max - min)) + min;
To get a random number say between 1 and 6, first do:
0.5 + (Math.random() * ((6 - 1) + 1))
This multiplies a random number by 6 and then adds 0.5 to it. Next round the number to a positive integer by doing:
Math.round(0.5 + (Math.random() * ((6 - 1) + 1))
This round the number to the nearest whole number.
Or to make it more understandable do this:
var value = 0.5 + (Math.random() * ((6 - 1) + 1))
var roll = Math.round(value);
return roll;
In general, the code for doing this using variables is:
var value = (Min - 0.5) + (Math.random() * ((Max - Min) + 1))
var roll = Math.round(value);
return roll;
The reason for taking away 0.5 from the minimum value is because using the minimum value alone would allow you to get an integer that was one more than your maximum value. By taking away 0.5 from the minimum value you are essentially preventing the maximum value from being rounded up.
Using the following code, you can generate an array of random numbers, without repeating, in a given range.
function genRandomNumber(how_many_numbers, min, max) {
// Parameters
//
// how_many_numbers: How many numbers you want to
// generate. For example, it is 5.
//
// min (inclusive): Minimum/low value of a range. It
// must be any positive integer, but
// less than max. I.e., 4.
//
// max (inclusive): Maximum value of a range. it must
// be any positive integer. I.e., 50
//
// Return type: array
var random_number = [];
for (var i = 0; i < how_many_numbers; i++) {
var gen_num = parseInt((Math.random() * (max-min+1)) + min);
do {
var is_exist = random_number.indexOf(gen_num);
if (is_exist >= 0) {
gen_num = parseInt((Math.random() * (max-min+1)) + min);
}
else {
random_number.push(gen_num);
is_exist = -2;
}
}
while (is_exist > -1);
}
document.getElementById('box').innerHTML = random_number;
}
Random whole number between lowest and highest:
function randomRange(low, high) {
var range = (high-low);
var random = Math.floor(Math.random()*range);
if (random === 0) {
random += 1;
}
return low + random;
}
It is not the most elegant solution, but something quick.
I found this simple method on W3Schools:
Math.floor((Math.random() * max) + min);
Math.random() is fast and suitable for many purposes, but it's not appropriate if you need cryptographically-secure values (it's not secure), or if you need integers from a completely uniform unbiased distribution (the multiplication approach used in others answers produces certain values slightly more often than others).
In such cases, we can use crypto.getRandomValues() to generate secure integers, and reject any generated values that we can't map uniformly into the target range. This will be slower, but it shouldn't be significant unless you're generating extremely large numbers of values.
To clarify the biased distribution concern, consider the case where we want to generate a value between 1 and 5, but we have a random number generator that produces values between 1 and 16 (a 4-bit value). We want to have the same number of generated values mapping to each output value, but 16 does not evenly divide by 5: it leaves a remainder of 1. So we need to reject 1 of the possible generated values, and only continue when we get one of the 15 lesser values that can be uniformly mapped into our target range. Our behaviour could look like this pseudocode:
Generate a 4-bit integer in the range 1-16.
If we generated 1, 6, or 11 then output 1.
If we generated 2, 7, or 12 then output 2.
If we generated 3, 8, or 13 then output 3.
If we generated 4, 9, or 14 then output 4.
If we generated 5, 10, or 15 then output 5.
If we generated 16 then reject it and try again.
The following code uses similar logic, but generates a 32-bit integer instead, because that's the largest common integer size that can be represented by JavaScript's standard number type. (This could be modified to use BigInts if you need a larger range.) Regardless of the chosen range, the fraction of generated values that are rejected will always be less than 0.5, so the expected number of rejections will always be less than 1.0 and usually close to 0.0; you don't need to worry about it looping forever.
const randomInteger = (min, max) => {
const range = max - min;
const maxGeneratedValue = 0xFFFFFFFF;
const possibleResultValues = range + 1;
const possibleGeneratedValues = maxGeneratedValue + 1;
const remainder = possibleGeneratedValues % possibleResultValues;
const maxUnbiased = maxGeneratedValue - remainder;
if (!Number.isInteger(min) || !Number.isInteger(max) ||
max > Number.MAX_SAFE_INTEGER || min < Number.MIN_SAFE_INTEGER) {
throw new Error('Arguments must be safe integers.');
} else if (range > maxGeneratedValue) {
throw new Error(`Range of ${range} (from ${min} to ${max}) > ${maxGeneratedValue}.`);
} else if (max < min) {
throw new Error(`max (${max}) must be >= min (${min}).`);
} else if (min === max) {
return min;
}
let generated;
do {
generated = crypto.getRandomValues(new Uint32Array(1))[0];
} while (generated > maxUnbiased);
return min + (generated % possibleResultValues);
};
console.log(randomInteger(-8, 8)); // -2
console.log(randomInteger(0, 0)); // 0
console.log(randomInteger(0, 0xFFFFFFFF)); // 944450079
console.log(randomInteger(-1, 0xFFFFFFFF));
// Error: Range of 4294967296 covering -1 to 4294967295 is > 4294967295.
console.log(new Array(12).fill().map(n => randomInteger(8, 12)));
// [11, 8, 8, 11, 10, 8, 8, 12, 12, 12, 9, 9]
Here is an example of a JavaScript function that can generate a random number of any specified length without using Math.random():
function genRandom(length)
{
const t1 = new Date().getMilliseconds();
var min = "1", max = "9";
var result;
var numLength = length;
if (numLength != 0)
{
for (var i = 1; i < numLength; i++)
{
min = min.toString() + "0";
max = max.toString() + "9";
}
}
else
{
min = 0;
max = 0;
return;
}
for (var i = min; i <= max; i++)
{
// Empty Loop
}
const t2 = new Date().getMilliseconds();
console.log(t2);
result = ((max - min)*t1)/t2;
console.log(result);
return result;
}
Use:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<script>
/*
Assuming that window.crypto.getRandomValues
is available, the real range would be from
0 to 1,998 instead of 0 to 2,000.
See the JavaScript documentation
for an explanation:
https://developer.mozilla.org/en-US/docs/Web/API/RandomSource/getRandomValues
*/
var array = new Uint8Array(2);
window.crypto.getRandomValues(array);
console.log(array[0] + array[1]);
</script>
</body>
</html>
Uint8Array creates an array filled with a number up to three digits which would be a maximum of 999. This code is very short.
This is my take on a random number in a range, as in I wanted to get a random number within a range of base to exponent. E.g., base = 10, exponent = 2, gives a random number from 0 to 100, ideally, and so on.
If it helps using it, here it is:
// Get random number within provided base + exponent
// By Goran Biljetina --> 2012
function isEmpty(value) {
return (typeof value === "undefined" || value === null);
}
var numSeq = new Array();
function add(num, seq) {
var toAdd = new Object();
toAdd.num = num;
toAdd.seq = seq;
numSeq[numSeq.length] = toAdd;
}
function fillNumSeq (num, seq) {
var n;
for(i=0; i<=seq; i++) {
n = Math.pow(num, i);
add(n, i);
}
}
function getRandNum(base, exp) {
if (isEmpty(base)) {
console.log("Specify value for base parameter");
}
if (isEmpty(exp)) {
console.log("Specify value for exponent parameter");
}
fillNumSeq(base, exp);
var emax;
var eseq;
var nseed;
var nspan;
emax = (numSeq.length);
eseq = Math.floor(Math.random()*emax) + 1;
nseed = numSeq[eseq].num;
nspan = Math.floor((Math.random())*(Math.random()*nseed)) + 1;
return Math.floor(Math.random()*nspan) + 1;
}
console.log(getRandNum(10, 20), numSeq);
//Testing:
//getRandNum(-10, 20);
//console.log(getRandNum(-10, 20), numSeq);
//console.log(numSeq);
This I guess, is the most simplified of all the contributions.
maxNum = 8,
minNum = 4
console.log(Math.floor(Math.random() * (maxNum - minNum) + minNum))
console.log(Math.floor(Math.random() * (8 - 4) + 4))
This will log random numbers between 4 and 8 into the console, 4 and 8 inclusive.
Ionuț G. Stan wrote a great answer, but it was a bit too complex for me to grasp. So, I found an even simpler explanation of the same concepts at Math.floor( Math.random () * (max - min + 1)) + min) Explanation by Jason Anello.
Note: The only important thing you should know before reading Jason's explanation is a definition of "truncate". He uses that term when describing Math.floor(). Oxford dictionary defines "truncate" as:
Shorten (something) by cutting off the top or end.
A function called randUpTo that accepts a number and returns a random whole number between 0 and that number:
var randUpTo = function(num) {
return Math.floor(Math.random() * (num - 1) + 0);
};
A function called randBetween that accepts two numbers representing a range and returns a random whole number between those two numbers:
var randBetween = function (min, max) {
return Math.floor(Math.random() * (max - min - 1)) + min;
};
A function called randFromTill that accepts two numbers representing a range and returns a random number between min (inclusive) and max (exclusive)
var randFromTill = function (min, max) {
return Math.random() * (max - min) + min;
};
A function called randFromTo that accepts two numbers representing a range and returns a random integer between min (inclusive) and max (inclusive):
var randFromTo = function (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
You can you this code snippet,
let randomNumber = function(first, second) {
let number = Math.floor(Math.random()*Math.floor(second));
while(number < first) {
number = Math.floor(Math.random()*Math.floor(second));
}
return number;
}
I currently need to round numbers up to their nearest major number. (Not sure what the right term is here)
But see an example of what I'm trying to achieve
IE:
13 // 20
349 // 400
5645 // 6000
9892 // 10000
13988 // 20000
93456 // 100000
231516 // 300000
etc. etc.
I have implemented a way of doing this but its so painful and only handles numbers up to a million and if I want it to go higher I need to add more if statements (yeah see how i implmented it :P im not very proud, but brain is stuck)
There must be something out there already but google is not helping me very much probably due to me not knowing the correct term for the kind of rounding i want to do
<script type="text/javascript">
function intelliRound(num) {
var len=(num+'').length;
var fac=Math.pow(10,len-1);
return Math.ceil(num/fac)*fac;
}
alert(intelliRound(13));
alert(intelliRound(349));
alert(intelliRound(5645));
// ...
</script>
See http://jsfiddle.net/fCLjp/
One way;
var a = [13, // 20
349, // 400
5645, // 6000
9892, // 10000
13988, // 20000
93456, // 100000
231516 // 300000
]
for (var i in a) {
var num = a[i];
var scale = Math.pow(10, Math.floor(Math.log(num) / Math.LN10));
print([ num, Math.ceil(num / scale) * scale ])
}
13,20
349,400
5645,6000
9892,10000
13988,20000
93456,100000
231516,300000
The answer from #rabudde works well, but for those that need to handle negative numbers, here's an updated version:
function intelliRound(num) {
var len = (num + '').length;
var result = 0;
if (num < 0) {
var fac = Math.pow(10, len - 2);
result = Math.floor(num / fac) * fac;
}
else {
var fac = Math.pow(10, len - 1);
result = Math.ceil(num / fac) * fac;
}
return result;
}
alert(intelliRound(13));
alert(intelliRound(349));
alert(intelliRound(5645));
alert(intelliRound(-13));
alert(intelliRound(-349));
alert(intelliRound(-5645));
you can use Math.ceil function, as described here:
javascript - ceiling of a dollar amount
to get your numbers right you'll have to divide them by 10 (if they have 2 digits), 100 (if they have 3 digits), and so on...
The intelliRound function from the other answers works well, but break with negative numbers. Here I have extended these solutions to support decimals (e.g. 0.123, -0.987) and non-numbers:
/**
* Function that returns the floor/ceil of a number, to an appropriate magnitude
* #param {number} num - the number you want to round
*
* e.g.
* magnitudeRound(0.13) => 1
* magnitudeRound(13) => 20
* magnitudeRound(349) => 400
* magnitudeRound(9645) => 10000
* magnitudeRound(-3645) => -4000
* magnitudeRound(-149) => -200
*/
function magnitudeRound(num) {
const isValidNumber = typeof num === 'number' && !Number.isNaN(num);
const result = 0;
if (!isValidNumber || num === 0) return result;
const abs = Math.abs(num);
const sign = Math.sign(num);
if (abs > 0 && abs <= 1) return 1 * sign; // percentages on a scale -1 to 1
if (abs > 1 && abs <= 10) return 10 * sign;
const zeroes = `${Math.round(abs)}`.length - 1; // e.g 123 => 2, 4567 => 3
const exponent = 10 ** zeroes; // math floor and ceil only work on integer
const roundingDirection = sign < 0 ? 'floor' : 'ceil';
return Math[roundingDirection](num / exponent) * exponent;
}