Javascript: Round up to the next multiple of 5 - javascript

I need a utility function that takes in an integer value (ranging from 2 to 5 digits in length) that rounds up to the next multiple of 5 instead of the nearest multiple of 5. Here is what I got:
function round5(x)
{
return (x % 5) >= 2.5 ? parseInt(x / 5) * 5 + 5 : parseInt(x / 5) * 5;
}
When I run round5(32), it gives me 30, where I want 35.
When I run round5(37), it gives me 35, where I want 40.
When I run round5(132), it gives me 130, where I want 135.
When I run round5(137), it gives me 135, where I want 140.
etc...
How do I do this?

This will do the work:
function round5(x)
{
return Math.ceil(x/5)*5;
}
It's just a variation of the common rounding number to nearest multiple of x function Math.round(number/x)*x, but using .ceil instead of .round makes it always round up instead of down/up according to mathematical rules.

const roundToNearest5 = x => Math.round(x/5)*5
This will round the number to the nearest 5. To always round up to the nearest 5, use Math.ceil. Likewise, to always round down, use Math.floor instead of Math.round.
You can then call this function like you would any other. For example,
roundToNearest5(21)
will return:
20

Like this?
function roundup5(x) { return (x%5)?x-x%5+5:x }

I arrived here while searching for something similar.
If my number is —0, —1, —2 it should floor to —0, and if it's —3, —4, —5 it should ceil to —5.
I came up with this solution:
function round(x) { return x%5<3 ? (x%5===0 ? x : Math.floor(x/5)*5) : Math.ceil(x/5)*5 }
And the tests:
for (var x=40; x<51; x++) {
console.log(x+"=>", x%5<3 ? (x%5===0 ? x : Math.floor(x/5)*5) : Math.ceil(x/5)*5)
}
// 40 => 40
// 41 => 40
// 42 => 40
// 43 => 45
// 44 => 45
// 45 => 45
// 46 => 45
// 47 => 45
// 48 => 50
// 49 => 50
// 50 => 50

voici 2 solutions possibles :
y= (x % 10==0) ? x : x-x%5 +5; //......... 15 => 20 ; 37 => 40 ; 41 => 45 ; 20 => 20 ;
z= (x % 5==0) ? x : x-x%5 +5; //......... 15 => 15 ; 37 => 40 ; 41 => 45 ; 20 => 20 ;
Regards
Paul

New answer for old question, without if nor Math
x % 5: the remainder
5 - x % 5: the amount need to add up
(5 - x % 5) % 5: make sure it less than 5
x + (5 - x % 5) % 5: the result (x or next multiple of 5)
~~((x + N - 1) / N): equivalent to Math.ceil(x / N)
function round5(x) {
return x + (5 - x % 5) % 5;
}
function nearest_multiple_of(N, x) {
return x + (N - x % N) % N;
}
function other_way_nearest_multiple_of(N, x) {
return ~~((x + N - 1) / N) * N;
}
console.info(nearest_multiple_of(5, 0)); // 0
console.info(nearest_multiple_of(5, 2022)); // 2025
console.info(nearest_multiple_of(5, 2025)); // 2025
console.info(other_way_nearest_multiple_of(5, 2022)); // 2025
console.info(other_way_nearest_multiple_of(5, 2025)); // 2025

// round with precision
var round = function (value, precision) {
return Math.round(value * Math.pow(10, precision)) / Math.pow(10, precision);
};
// round to 5 with precision
var round5 = (value, precision) => {
return round(value * 2, precision) / 2;
}

const fn = _num =>{
return Math.round(_num)+ (5 -(Math.round(_num)%5))
}
reason for using round is that expected input can be a random number.
Thanks!!!

I solved it using a while loop, or any other loop for that matter. What is important is to increase the number say n, until n % 5 == 0; Something like this
while(n % 5 != 0) {
n++;
}
return n;

if( x % 5 == 0 ) {
return int( Math.floor( x / 5 ) ) * 5;
} else {
return ( int( Math.floor( x / 5 ) ) * 5 ) + 5;
}
maybe?

Related

i wanna solve using recursive function.. but can't solve it

function test3(num) {
value = value * Number(str[i]);
let value = 1;
let str = String(num);
for (let i = 0; i < str.length; i++) {
if (str.length <= 1) {
}
return test3(value);
}
return value;
}
i wanna make single Digits using recursive function.
but, the code's value can't access..
i m searching in google about recursive fuction, it's not good answer..
why cant access 'value' ?
i wanna make
234,
2* 3* 4
2* 4
8
786,
7 * 8 * 6 -> 336
3 * 3 * 6 -> 54
5 * 4 -> 20
2 * 0 -> 0
like that. i want to know why can't access 'value' in the function.
thank you.
You can't access variables form the parent function's scope. If you want to access variables, pass them in as a parameter. Regardless, this is much easier done without strings:
function productOfDigits(num) {
if (num < 10) {
return num;
}
return (num % 10) * productOfDigits(Math.floor(num / 10));
}
// use this one
function repeatedProductOfDigits(num) {
if (num < 10) {
return num;
}
// multiply all the digits then try again
return repeatedProductOfDigits(productOfDigits(num));
}
num % 10 gets the last digit, and Math.floor(num / 10) gets every digit except the last, so productOfDigits(786) == 6 * productOfDigits(78) == 6 * 8 * productOfDigits(7) == 6 * 8 * 7.
It looks like you are trying to calculate the multiplicative digital root -
const multRoot = n =>
n < 10
? n
: multRoot(product(digits(n)))
const digits = n =>
n < 10
? [ n ]
: [ ...digits(Math.floor(n / 10)), n % 10 ]
const product = ns =>
ns.reduce(mult, 1)
const mult = (m, n) =>
m * n
console.log(multRoot(234)) // 8
console.log(multRoot(786)) // 0
To see a variant of this problem, read this Q&A.

Check whether a number is divisible by another number If not make it divisable in Javascript

I want to check whether a number (7) is divisible by another number (5), If the number is divisible by the number then I need to return the same number. If the number is not divisible by another number I need to make it divisible and return the updated value.
var i =7;
if (i % 5 == 0) {
alert("divisible by 5");
} else {
alert("divisible not by 5");
}
Here if the condition satisfy then I need to return the same value. If the condition is not satisfied I need to add the required number and make it next divisible. (Like 7 is not divisible by 5 so I need add 3 to 7 and return the value 10 which is divisible by 5).
Are there any Math functions exists to implement the same?
What you want, it seems like, is this:
function roundTo(n, d) {
return Math.floor((n + d - 1) / d) * d;
}
For n 10 and d 5, you get 10 back. For n 7 and d 5, you also get 10. What the code does is add one less than the divisor to the input number, and then divides by the divisor. It then gets rid of any fractional part (Math.floor()) and multiplies by the divisor again.
You can do that by using a simple while loop:
function doThat(number, divider) {
while(number % divider !== 0) {
number++;
}
return number;
}
doThat(12, 5); // => returns 15
Here's a fiddle: https://jsfiddle.net/rdko8dmb/
You could use this algorithm:
i % n = r, where i = 7, n = 5, and r = 2.
Then, make i = i + (n - r). i.e. i = 7 + (5-2) → 10. Then you can use this for your division.
Try this
function divisible(dividend, divisor){
if (dividend % divisor == 0) {
return dividend;
} else {
var num = dividend + (divisor-(dividend % divisor));
return num;
}
}
var res = divisible(7, 5);
console.log(res);
Here is the fastest and cleanest way to do that:
function shift(number, divider)
{
return number + (divider - (number % divider)) % divider;
}
It takes number and moves it up by the difference from (our unit) divider to the remainder to make it divisible by the divider. The % divider makes sure that if there is no difference number doesn't get pushed up by a full unit of the divider.
I do not know if this will work for all numbers... But you might try this
7 % 5 = 2. If you subtract 2 from 5 you will get 3... This is the number you need to add to 7. 16 % 5 = 1 subtract 1 from 5 = 4 .. 4 + 16 = 20
Another example 16 % 13 = 3 ... 13-3 = 10 16+10 = 26 26/13 = 2
Here's an example of function that finds next higher natural number that is divisble by y
https://www.jschallenger.com/javascript-basics/find-next-higher-number
Option 1
while (x % y !== 0) x++;
return x;
}
Option 2
if(x % y == 0){
return x;
}
else{
for(i = x+1; i > x; i++){
if(i % y == 0){
return i;
}
}
}

Using Javascript to convert radians to degrees with positive and negative values [duplicate]

According to Google Calculator (-13) % 64 is 51.
According to Javascript (see this JSBin) it is -13.
How do I fix this?
Number.prototype.mod = function (n) {
"use strict";
return ((this % n) + n) % n;
};
Taken from this article: The JavaScript Modulo Bug
Using Number.prototype is SLOW, because each time you use the prototype method your number is wrapped in an Object. Instead of this:
Number.prototype.mod = function(n) {
return ((this % n) + n) % n;
}
Use:
function mod(n, m) {
return ((n % m) + m) % m;
}
See: https://jsperf.app/negative-modulo/2
~97% faster than using prototype. If performance is of importance to you of course..
The % operator in JavaScript is the remainder operator, not the modulo operator (the main difference being in how negative numbers are treated):
-1 % 8 // -1, not 7
A "mod" function to return a positive result.
var mod = function (n, m) {
var remain = n % m;
return Math.floor(remain >= 0 ? remain : remain + m);
};
mod(5,22) // 5
mod(25,22) // 3
mod(-1,22) // 21
mod(-2,22) // 20
mod(0,22) // 0
mod(-1,22) // 21
mod(-21,22) // 1
And of course
mod(-13,64) // 51
The accepted answer makes me a little nervous because it re-uses the % operator. What if Javascript changes the behavior in the future?
Here is a workaround that does not re-use %:
function mod(a, n) {
return a - (n * Math.floor(a/n));
}
mod(1,64); // 1
mod(63,64); // 63
mod(64,64); // 0
mod(65,64); // 1
mod(0,64); // 0
mod(-1,64); // 63
mod(-13,64); // 51
mod(-63,64); // 1
mod(-64,64); // 0
mod(-65,64); // 63
If x is an integer and n is a power of 2, you can use x & (n - 1) instead of x % n.
> -13 & (64 - 1)
51
Fix negative modulo (reminder operator %)
Simplified using ES6 Arrow function, and without dangerously extending the Number prototype
const mod = (n, m) => (n % m + m) % m;
console.log(mod(-90, 360)); // 270 (Instead of -90)
Though it isn't behaving as you expected, it doesn't mean that JavaScript is not 'behaving'. It is a choice JavaScript made for its modulo calculation. Because, by definition either answer makes sense.
See this from Wikipedia. You can see on the right how different languages chose the result's sign.
This is not a bug, there's 3 functions to calculate modulo, you can use the one which fit your needs (I would recommend to use Euclidean function)
Truncating the decimal part function
console.log( 41 % 7 ); // 6
console.log( -41 % 7 ); // -6
console.log( -41 % -7 ); // -6
console.log( 41 % -7 ); // 6
Integer part function
Number.prototype.mod = function(n) {
return ((this%n)+n)%n;
};
console.log( parseInt( 41).mod( 7) ); // 6
console.log( parseInt(-41).mod( 7) ); // 1
console.log( parseInt(-41).mod(-7) ); // -6
console.log( parseInt( 41).mod(-7) ); // -1
Euclidean function
Number.prototype.mod = function(n) {
var m = ((this%n)+n)%n;
return m < 0 ? m + Math.abs(n) : m;
};
console.log( parseInt( 41).mod( 7) ); // 6
console.log( parseInt(-41).mod( 7) ); // 1
console.log( parseInt(-41).mod(-7) ); // 1
console.log( parseInt( 41).mod(-7) ); // 6
So it seems that if you're trying to mod around degrees (so that if you have -50 degrees - 200 degrees), you'd want to use something like:
function modrad(m) {
return ((((180+m) % 360) + 360) % 360)-180;
}
I deal with négative a and negative n too
//best perf, hard to read
function modul3(a,n){
r = a/n | 0 ;
if(a < 0){
r += n < 0 ? 1 : -1
}
return a - n * r
}
// shorter code
function modul(a,n){
return a%n + (a < 0 && Math.abs(n));
}
//beetween perf and small code
function modul(a,n){
return a - n * Math[n > 0 ? 'floor' : 'ceil'](a/n);
}
There is a NPM package that will do the work for you. You can install it with the following command.
npm install just-modulo --save
Usage copied from the README
import modulo from 'just-modulo';
modulo(7, 5); // 2
modulo(17, 23); // 17
modulo(16.2, 3.8); // 17
modulo(5.8, 3.4); //2.4
modulo(4, 0); // 4
modulo(-7, 5); // 3
modulo(-2, 15); // 13
modulo(-5.8, 3.4); // 1
modulo(12, -1); // NaN
modulo(-3, -8); // NaN
modulo(12, 'apple'); // NaN
modulo('bee', 9); // NaN
modulo(null, undefined); // NaN
GitHub repository can be found via the following link:
https://github.com/angus-c/just/tree/master/packages/number-modulo
For fun, here's a "wrap" function that works sorta like a modulo, except you can also specify the minimum value of the range (instead of it being 0):
const wrap = (value = 0, min = 0, max = 10) =>
((((value - min) % (max - min)) + (max - min)) % (max - min)) + min;
Basically just takes the true modulo formula, offsets it such that min ends up at 0, then adds min back in after.
Useful if you have a value that you want to keep between two values.

JavaScript % (modulo) gives a negative result for negative numbers

According to Google Calculator (-13) % 64 is 51.
According to Javascript (see this JSBin) it is -13.
How do I fix this?
Number.prototype.mod = function (n) {
"use strict";
return ((this % n) + n) % n;
};
Taken from this article: The JavaScript Modulo Bug
Using Number.prototype is SLOW, because each time you use the prototype method your number is wrapped in an Object. Instead of this:
Number.prototype.mod = function(n) {
return ((this % n) + n) % n;
}
Use:
function mod(n, m) {
return ((n % m) + m) % m;
}
See: https://jsperf.app/negative-modulo/2
~97% faster than using prototype. If performance is of importance to you of course..
The % operator in JavaScript is the remainder operator, not the modulo operator (the main difference being in how negative numbers are treated):
-1 % 8 // -1, not 7
A "mod" function to return a positive result.
var mod = function (n, m) {
var remain = n % m;
return Math.floor(remain >= 0 ? remain : remain + m);
};
mod(5,22) // 5
mod(25,22) // 3
mod(-1,22) // 21
mod(-2,22) // 20
mod(0,22) // 0
mod(-1,22) // 21
mod(-21,22) // 1
And of course
mod(-13,64) // 51
The accepted answer makes me a little nervous because it re-uses the % operator. What if Javascript changes the behavior in the future?
Here is a workaround that does not re-use %:
function mod(a, n) {
return a - (n * Math.floor(a/n));
}
mod(1,64); // 1
mod(63,64); // 63
mod(64,64); // 0
mod(65,64); // 1
mod(0,64); // 0
mod(-1,64); // 63
mod(-13,64); // 51
mod(-63,64); // 1
mod(-64,64); // 0
mod(-65,64); // 63
If x is an integer and n is a power of 2, you can use x & (n - 1) instead of x % n.
> -13 & (64 - 1)
51
Fix negative modulo (reminder operator %)
Simplified using ES6 Arrow function, and without dangerously extending the Number prototype
const mod = (n, m) => (n % m + m) % m;
console.log(mod(-90, 360)); // 270 (Instead of -90)
Though it isn't behaving as you expected, it doesn't mean that JavaScript is not 'behaving'. It is a choice JavaScript made for its modulo calculation. Because, by definition either answer makes sense.
See this from Wikipedia. You can see on the right how different languages chose the result's sign.
This is not a bug, there's 3 functions to calculate modulo, you can use the one which fit your needs (I would recommend to use Euclidean function)
Truncating the decimal part function
console.log( 41 % 7 ); // 6
console.log( -41 % 7 ); // -6
console.log( -41 % -7 ); // -6
console.log( 41 % -7 ); // 6
Integer part function
Number.prototype.mod = function(n) {
return ((this%n)+n)%n;
};
console.log( parseInt( 41).mod( 7) ); // 6
console.log( parseInt(-41).mod( 7) ); // 1
console.log( parseInt(-41).mod(-7) ); // -6
console.log( parseInt( 41).mod(-7) ); // -1
Euclidean function
Number.prototype.mod = function(n) {
var m = ((this%n)+n)%n;
return m < 0 ? m + Math.abs(n) : m;
};
console.log( parseInt( 41).mod( 7) ); // 6
console.log( parseInt(-41).mod( 7) ); // 1
console.log( parseInt(-41).mod(-7) ); // 1
console.log( parseInt( 41).mod(-7) ); // 6
So it seems that if you're trying to mod around degrees (so that if you have -50 degrees - 200 degrees), you'd want to use something like:
function modrad(m) {
return ((((180+m) % 360) + 360) % 360)-180;
}
I deal with négative a and negative n too
//best perf, hard to read
function modul3(a,n){
r = a/n | 0 ;
if(a < 0){
r += n < 0 ? 1 : -1
}
return a - n * r
}
// shorter code
function modul(a,n){
return a%n + (a < 0 && Math.abs(n));
}
//beetween perf and small code
function modul(a,n){
return a - n * Math[n > 0 ? 'floor' : 'ceil'](a/n);
}
There is a NPM package that will do the work for you. You can install it with the following command.
npm install just-modulo --save
Usage copied from the README
import modulo from 'just-modulo';
modulo(7, 5); // 2
modulo(17, 23); // 17
modulo(16.2, 3.8); // 17
modulo(5.8, 3.4); //2.4
modulo(4, 0); // 4
modulo(-7, 5); // 3
modulo(-2, 15); // 13
modulo(-5.8, 3.4); // 1
modulo(12, -1); // NaN
modulo(-3, -8); // NaN
modulo(12, 'apple'); // NaN
modulo('bee', 9); // NaN
modulo(null, undefined); // NaN
GitHub repository can be found via the following link:
https://github.com/angus-c/just/tree/master/packages/number-modulo
For fun, here's a "wrap" function that works sorta like a modulo, except you can also specify the minimum value of the range (instead of it being 0):
const wrap = (value = 0, min = 0, max = 10) =>
((((value - min) % (max - min)) + (max - min)) % (max - min)) + min;
Basically just takes the true modulo formula, offsets it such that min ends up at 0, then adds min back in after.
Useful if you have a value that you want to keep between two values.

Gaussian/banker's rounding in JavaScript

I have been using Math.Round(myNumber, MidpointRounding.ToEven) in C# to do my server-side rounding, however, the user needs to know 'live' what the result of the server-side operation will be which means (avoiding an Ajax request) creating a JavaScript method to replicate the MidpointRounding.ToEven method used by C#.
MidpointRounding.ToEven is Gaussian/banker's rounding, a very common rounding method for accounting systems described here.
Does anyone have any experience with this? I have found examples online, but they do not round to a given number of decimal places...
function evenRound(num, decimalPlaces) {
var d = decimalPlaces || 0;
var m = Math.pow(10, d);
var n = +(d ? num * m : num).toFixed(8); // Avoid rounding errors
var i = Math.floor(n), f = n - i;
var e = 1e-8; // Allow for rounding errors in f
var r = (f > 0.5 - e && f < 0.5 + e) ?
((i % 2 == 0) ? i : i + 1) : Math.round(n);
return d ? r / m : r;
}
console.log( evenRound(1.5) ); // 2
console.log( evenRound(2.5) ); // 2
console.log( evenRound(1.535, 2) ); // 1.54
console.log( evenRound(1.525, 2) ); // 1.52
Live demo: http://jsfiddle.net/NbvBp/
For what looks like a more rigorous treatment of this (I've never used it), you could try this BigNumber implementation.
This is the unusual stackoverflow where the bottom answers are better than the accepted. Just cleaned up #xims solution and made a bit more legible:
function bankersRound(n, d=2) {
var x = n * Math.pow(10, d);
var r = Math.round(x);
var br = Math.abs(x) % 1 === 0.5 ? (r % 2 === 0 ? r : r-1) : r;
return br / Math.pow(10, d);
}
That's a great solution from #soegaard.
Here is a small change that makes it work for decimal points:
bankers_round(n:number, d:number=0) {
var x = n * Math.pow(10, d);
var r = Math.round(x);
var br = (((((x>0)?x:(-x))%1)===0.5)?(((0===(r%2)))?r:(r-1)):r);
return br / Math.pow(10, d);
}
And while at it - here are some tests:
console.log(" 1.5 -> 2 : ", bankers_round(1.5) );
console.log(" 2.5 -> 2 : ", bankers_round(2.5) );
console.log(" 1.535 -> 1.54 : ", bankers_round(1.535, 2) );
console.log(" 1.525 -> 1.52 : ", bankers_round(1.525, 2) );
console.log(" 0.5 -> 0 : ", bankers_round(0.5) );
console.log(" 1.5 -> 2 : ", bankers_round(1.5) );
console.log(" 0.4 -> 0 : ", bankers_round(0.4) );
console.log(" 0.6 -> 1 : ", bankers_round(0.6) );
console.log(" 1.4 -> 1 : ", bankers_round(1.4) );
console.log(" 1.6 -> 2 : ", bankers_round(1.6) );
console.log(" 23.5 -> 24 : ", bankers_round(23.5) );
console.log(" 24.5 -> 24 : ", bankers_round(24.5) );
console.log(" -23.5 -> -24 : ", bankers_round(-23.5) );
console.log(" -24.5 -> -24 : ", bankers_round(-24.5) );
The accepted answer does round to a given number of places. In the process it calls toFixed which converts the number to a string. Since this is expensive, I offer the solution below. It rounds a number ending in 0.5 to the nearest even number. It does not handle rounding to an arbitrary number of places.
function even_p(n){
return (0===(n%2));
};
function bankers_round(x){
var r = Math.round(x);
return (((((x>0)?x:(-x))%1)===0.5)?((even_p(r))?r:(r-1)):r);
};
I was not happy with the other answers. They have either too verbose or complicated code or fail to round properly for negative numbers. For negative numbers we have to cleverly fix a weird behavior of JavaScript:
JavaScript's Math.round has the unusual property that it rounds halfway cases towards positive infinity, regardless of whether they're positive or negative. So for example 2.5 will round to 3.0, but -2.5 will round to -2.0.
Source
This is wrong, so we have to round down on negatives .5 before applying the bankers rounding, accordantly.
Also, just as Math.round, I want to round to the next integer and enforce a precision of 0. I just want Math.round with the correct and fixed "round halves to even" method in positive and negative. It needs to round the same like in other programming languages such as PHP (PHP_ROUND_HALF_EVEN) or C# (MidpointRounding.ToEven).
/**
* Returns a supplied numeric expression rounded to the nearest integer while rounding halves to even.
*/
function roundMidpointToEven(x) {
const n = x >= 0 ? 1 : -1 // n describes the adjustment on an odd rounding from midpoint
const r = n * Math.round(n * x) // multiplying n will fix negative rounding
return Math.abs(x) % 1 === 0.5 && r % 2 !== 0 ? r - n : r // we adjust by n if we deal with a half on an odd rounded number
}
// testing by rounding cents:
for(let i = -10; i <= 10; i++) {
const val = i + .5
console.log(val + " => " + roundMidpointToEven(val))
}
Math.round as well as our custom roundMidpointToEven function won't care for precision, because it's always better to calculate with cents to avoid float-point issues on any calculations anyways.
However, if you don't deal with cents you can simply multiply and divide the appropriate factor for the number of decimal placeholders in the same way you would do it for Math.round:
const usd = 9.225;
const fact = Math.pow(10, 2) // A precision of 2, so 100 is the factor
console.log(roundMidpointToEven(usd * fact) / fact) // outputs 9.22 instead of 9.23
To fully validate the custom roundMidpointToEven function, here is the same output using PHP with its official PHP_ROUND_HALF_EVEN as well as C# using MidpointRounding.ToEven:
for($i = -10; $i <= 10; $i++) {
$val = $i + .5;
echo $val . ' => ' . round($val, 0, PHP_ROUND_HALF_EVEN) . "<br />";
}
for(int i = -10; i <= 10; i++)
{
double val = i + .5;
Console.WriteLine(val + " => " + Math.Round(val, MidpointRounding.ToEven));
}
Both snippets return the same like the test call of our custom roundMidpointToEven:
-9.5 => -10
-8.5 => -8
-7.5 => -8
-6.5 => -6
-5.5 => -6
-4.5 => -4
-3.5 => -4
-2.5 => -2
-1.5 => -2
-0.5 => 0
0.5 => 0
1.5 => 2
2.5 => 2
3.5 => 4
4.5 => 4
5.5 => 6
6.5 => 6
7.5 => 8
8.5 => 8
9.5 => 10
10.5 => 10
Success!
const isEven = (value: number) => value % 2 === 0;
const isHalf = (value: number) => {
const epsilon = 1e-8;
const remainder = Math.abs(value) % 1;
return remainder > .5 - epsilon && remainder < .5 + epsilon;
};
const roundHalfToEvenShifted = (value: number, factor: number) => {
const shifted = value * factor;
const rounded = Math.round(shifted);
const modifier = value < 0 ? -1 : 1;
return !isEven(rounded) && isHalf(shifted) ? rounded - modifier : rounded;
};
const roundHalfToEven = (digits: number, unshift: boolean) => {
const factor = 10 ** digits;
return unshift
? (value: number) => roundHalfToEvenShifted(value, factor) / factor
: (value: number) => roundHalfToEvenShifted(value, factor);
};
const roundDollarsToCents = roundHalfToEven(2, false);
const roundCurrency = roundHalfToEven(2, true);
If you do not like the overhead of calling toFixed()
Want to be able to supply an arbitrary scale
Don't want to introduce floating-point errors
Want to have readable, reusable code
roundHalfToEven is a function that generates a fixed scale rounding function. I do my currency operations on cents, rather than dollars, to avoid introducing FPEs. The unshift param exists to avoid the overhead of unshifting and shifting again for those operations.
Stricly speaking, all of these implementations should handle the case of a negative number of digits to round to.
It is an edge case, but still it would be wise to disallow it (or be very clear about what that means, for example -2 is rounding to the nearest amount of hundreds).
This solution is slightly more elegant than any of the current answers. It handles rounding negative numbers and negative number of decimal places correct.
function bankersRound (value, nDec = 2) {
let x = value * Math.pow(10, nDec);
let r = Math.round(x);
return (Math.abs(x) % 1 === .5 ? r - (r % 2) : r) / Math.pow(10, nDec);
}
For folks who want to be able to read the code a little better, here's an alternative implementation that seems to work.
function bankersRound(n, decimalPlaces) {
// Create our multiplier for floating point precision issues.
const multiplier = Math.pow(10, decimalPlaces);
// Multiple by decimal places to avoid rounding issues w/ floats
const num = n * multiplier;
// Use standard rounding
const rounded = Math.round(num);
// Only odd numbers should be rounded
const shouldUseBankersRound = rounded % 2 !== 0;
// Subtract one to ensure the rounded number is even
const bankersRound = shouldUseBankersRound ? rounded - 1 : rounded;
// Return to original precision
return bankersRound / multiplier;
}
console.log(
bankersRound(1.5255, 2),
bankersRound(1.53543, 2),
bankersRound(1.54543, 2),
bankersRound(1.54543, 3),
bankersRound(1.53529, 4),
bankersRound(1.53529, 2),
bankersRound(4.5, 0),
bankersRound(5.5, 0),
bankersRound(0.045, 2),
bankersRound(0.055, 2)
);

Categories

Resources