JavaScript has some inaccurate rounding behavior so I've been looking for a reliable solution without success. There are many answers in this SO post but none cover all the edge cases as far as I can tell. I wrote the following which handles all the edge cases presented. Will it be reliable with edge cases I haven't tested?If this is a viable solution, any enhancements to make it more efficient would be appreciated. It's not fast (time to run function 1000000 times: 778ms) but doesn't seem to be  terrible either. If there is a better solution, please post.The edge cases that seemed to give the most problem were the first two:console.log(round(1.005, 2)); // 1.01console.log(round(1234.00000254495, 10)); //1234.000002545console.log(round(1835.665, 2)); // 1835.67))console.log(round(-1835.665, 2)); // -1835.67))console.log(round(10.8034, 2)); // 10.8console.log(round(1.275, 2)); // 1.28console.log(round(1.27499, 2)); // 1.27console.log(round(1.2345678e+2, 2)); // 123.46console.log(round(1234.5678, -1)); // 1230console.log(round(1235.5678, -1)); // 1240console.log(round(1234.5678, -2)); // 1200console.log(round(1254.5678, -2)); // 1300console.log(round(1254, 2)); // 1254console.log(round(123.45)); // 123console.log(round(123.55)); // 124function round(number, precision) {  precision = precision ? precision : 0;  var sNumber =  + number;  var a = sNumber.split(.);  if (a.length == 1 || precision < 0) {    // from MDN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round    var factor = Math.pow(10, precision);    var tempNumber = number * factor;    var roundedTempNumber = Math.round(tempNumber);    return roundedTempNumber / factor;  }  // use one decimal place beyond the precision  var factor = Math.pow(10, precision + 1);  // separate out decimals and trim or pad as necessary  var sDec = a[1].substr(0, precision + 1);  if (sDec.length < precision + 1) {    for (var i = 0; i < (precision - sDec.length); i++)      sDec = sDec.concat(0);  }  // put the number back together  var sNumber = a[0] + . + sDec;  var number = parseFloat(sNumber);  // test the last digit  var last = sDec.substr(sDec.length - 1);  if (last >= 5) {    // round up by correcting float error    // UPDATED - for negative numbers will round away from 0     // e.g. round(-2.5, 0) == -3            number += 1/(factor) * (+number < 0 ? -1 : 1);  }  number = +number.toFixed(precision);  return number;};
Rounding JavaScript decimals
javascript;floating point
Here is my solution that I came up with by starting off from your own code, which as I was tracing the logic I realized was a bit bloated, through quite efficient. What's more, when I was adding a few more test cases I discovered 2 bugs in it. I also did benchmark of your, @mseifert and mine code.But first, few comments about your code:You have quite numerous unnecessary (in my opinion) variables,The loop and surrounding conditional statement is completely unnecessary as well,Variables' names could be more descriptive, especially a's,sDec += '0' is shorter and faster than sDec = sDec.concat(0),Why to assign +number.toFixed(precision) to variable number, if in the very next line you just return number? Go with return +number.toFixed(precision) instead.Test casesJust one note: this is definitely not the elegant way of writing tests, but test cases themselves weren't in the scope of this question, so I allowed myself to do it this way.Two lines with comments next to them are those which revealed bugs in your original code to me.console.clear();console.log(round(1.0e-5, 5) === 0.00001);console.log(round(1.0e-20, 20) === 1e-20);console.log(round(1.0e20, 2) === 100000000000000000000);console.log(round(1.005, 2) === 1.01);console.log(round(1234.00000254495, 10) === 1234.000002545);console.log(round(1835.665, 2) === 1835.67);console.log(round(-1835.665, 2) === -1835.67);console.log(round(1.27499, 2) === 1.27);console.log(round(1.2345678e+2, 2) === 123.46);console.log(round(1234.5678, -1) === 1230);console.log(round(1234.5678, -2) === 1200);console.log(round(1254.5678, -2) === 1300);console.log(round(1254, 2) === 1254);console.log(round(1254) === 1254);console.log(round('1254') === 1254);console.log(round('123.55') === 124);console.log(round('123.55', 1) === 123.6);console.log(round('123.55', '1') === 123.6);console.log(round(123.55, '1') === 123.6);console.log(round('-1835.665', 2) === -1835.67);console.log(round('-1835.665', '2') === -1835.67); // Made me turn precision into +precisionconsole.log(round(-1835.665, '2') === -1835.67);console.log(round('1.0e-5', 5) === 0.00001); // Made me add number = +number;console.log(round('1.0e-5', '5') === 0.00001);console.log(round(1.0e-5, '5') === 0.00001);console.log(round('1.0e-20', 20) === 1e-20);console.log(round('1.0e-20', '20') === 1e-20);console.log(round(1.0e-20, '20') === 1e-20);console.log(round('1.0e20', 2) === 100000000000000000000);console.log(round('1.0e20', '2') === 100000000000000000000);console.log(round(1.0e20, '2') === 100000000000000000000);BenchmarkNotice that my code is not much faster than yours.(made with JSBench.Me and using Chrome 57)Complete codeYou can change the only var keyword to const from ES6 if you want to use it, since the variables that this keyword applies to are indeed constant.function round(number, precision) {    'use strict';    precision = precision ? +precision : 0;    var sNumber     = number + '',        periodIndex = sNumber.indexOf('.'),        factor      = Math.pow(10, precision);    if (periodIndex === -1 || precision < 0) {        return Math.round(number * factor) / factor;    }    number = +number;    // sNumber[periodIndex + precision + 1] is the last digit    if (sNumber[periodIndex + precision + 1] >= 5) {        // Correcting float error        // factor * 10 to use one decimal place beyond the precision        number += (number < 0 ? -1 : 1) / (factor * 10);    }    return +number.toFixed(precision);}