Skip to content

Instantly share code, notes, and snippets.

@jwilson8767
Created April 28, 2020 21:43
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jwilson8767/ce39efd11ac69f253f5c1478cad0286c to your computer and use it in GitHub Desktop.
Save jwilson8767/ce39efd11ac69f253f5c1478cad0286c to your computer and use it in GitHub Desktop.
More javascript rounding options!
/*
I had trouble finding simple methods for rounding modes like half-even and
half-away-from-zero in Javascript, so here's what I came up with! Enjoy!
MIT licensed
*/
/**
* Applies half-even rounding to the given number of significant figures. Supports n as a single value or series.
* @param {number} x Number to round
* @param {int} n Number of significant figures
* @return {number}
*/
export function round_to_n_significant_figures(x, n) {
if ( n < 1){
throw Error('Cannot round to less than 1 significant figures!')
}
return round_half_even(x, -Math.trunc(Math.floor(Math.log10(Math.abs(x)))) + (n - 1))
}
/**
* Returns a number rounded using half-even rounding. Non-numeric values return NAN. Should match behavior of Python's round() function.
* @param {number} x Number to round
* @param {int} n Number of digits after the decimal point. May be negative to do things like `round_half_even(2500, -3) -> 2000`.
* @return {number}
*/
export function round_half_even(x, n){
x = Number(x);
if (Number.isNaN(x) || !Number.isFinite(x) || x === 0){
return x
}
if (x < 0){
return -round_half_even(-x, n)
}
x = x * Math.pow(10, n);
// figure out if the value is going to be a "half" value
const half = (x - Math.floor(x)) === 0.5;
// use Math.rounding (which uses half-up rounding), if not half not even, then subtract 1.
x = Math.round(x)
if (half && (x % 2 !== 0)){
x = x - 1;
}
x = x / Math.pow(10, n)
return x
}
/**
* Returns a number rounded using half-away-from-0 rounding.
* @param {number} x Number to round
* @param {int} n Number of digits after the decimal point. May be negative to do things like `round_half_away_from_zero(2500, -3) -> 3000`.
* @return {number}
*/
export function round_half_away_from_zero(x, n){
x = Number(x);
if (Number.isNaN(x) || !Number.isFinite(x) || x === 0){
return x
}
if (x < 0){
// negative values just get inverted so we can use Math.round's half-up rounding
return -round_half_away_from_zero(-x, n)
}
return Math.round(x * Math.pow(10, n)) / Math.pow(10, n);
}
/**
* Returns a number rounded using half-toward-0 rounding.
* @param {number} x Number to round
* @param {int} n Number of digits after the decimal point. May be negative to do things like `round_half_toward_from_zero(2500, -3) -> 2000`.
* @return {number}
*/
export function round_half_toward_from_zero(x, n){
x = Number(x)
if (Number.isNaN(x) || x === 0){
return x
}
if (x > 0){
// negative values just get inverted so we can use Math.round's half-up rounding
return -round_half_away_from_zero(-x, n)
}
return Math.round(x * Math.pow(10, n-1)) / Math.pow(10, n-1);
}
@jwilson8767
Copy link
Author

I do have a Python version of round_to_n_significant_figures as well, but you can probably just write the conversion yourself! Just remember that Python's round() does half-even rounding.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment