var numb = 1.5;numb = +numb.toFixed(2);// Note the plus sign that drops any "extra" zeroes at the end.// It changes the result (which is a string) into a number again (think "0 + foo"),// which means that it uses only as many digits as necessary.
parseFloat("1.555").toFixed(2); // Returns 1.55 instead of 1.56.parseFloat("1.5550").toFixed(2); // Returns 1.55 instead of 1.56.// However, it will return correct result if you round 1.5551.parseFloat("1.5551").toFixed(2); // Returns 1.56 as expected.
1.3555.toFixed(3) // Returns 1.355 instead of expected 1.356.// However, it will return correct result if you round 1.35551.1.35551.toFixed(2); // Returns 1.36 as expected.
function ConvertToDecimal(num) {num = num.toString(); // If it's not already a Stringnum = num.slice(0, (num.indexOf(".")) + 3); // With 3 exposing the hundredths placealert('M : ' + Number(num)); // If you need it back as a Number}
number = 16.6666666;console.log(parseFloat(number.toFixed(2)));"16.67"
number = 16.6;console.log(parseFloat(number.toFixed(2)));"16.6"
number = 16;console.log(parseFloat(number.toFixed(2)));"16"
/*** Converts num to a decimal string (if it isn't one already) and then rounds it* to at most dp decimal places.** For explanation of why you'd want to perform rounding operations on a String* rather than a Number, see http://stackoverflow.com/a/38676273/1709587** @param {(number|string)} num* @param {number} dp* @return {string}*/function roundStringNumberWithoutTrailingZeroes (num, dp) {if (arguments.length != 2) throw new Error("2 arguments required");
num = String(num);if (num.indexOf('e+') != -1) {// Can't round numbers this large because their string representation// contains an exponent, like 9.99e+37throw new Error("num too large");}if (num.indexOf('.') == -1) {// Nothing to doreturn num;}
var parts = num.split('.'),beforePoint = parts[0],afterPoint = parts[1],shouldRoundUp = afterPoint[dp] >= 5,finalNumber;
afterPoint = afterPoint.slice(0, dp);if (!shouldRoundUp) {finalNumber = beforePoint + '.' + afterPoint;} else if (/^9+$/.test(afterPoint)) {// If we need to round up a number like 1.9999, increment the integer// before the decimal point and discard the fractional part.finalNumber = Number(beforePoint)+1;} else {// Starting from the last digit, increment digits until we find one// that is not 9, then stopvar i = dp-1;while (true) {if (afterPoint[i] == '9') {afterPoint = afterPoint.substr(0, i) +'0' +afterPoint.substr(i+1);i--;} else {afterPoint = afterPoint.substr(0, i) +(Number(afterPoint[i]) + 1) +afterPoint.substr(i+1);break;}}
finalNumber = beforePoint + '.' + afterPoint;}
// Remove trailing zeroes from fractional part before returningreturn finalNumber.replace(/0+$/, '')}
/*** Takes a float and rounds it to at most dp decimal places. For example** roundFloatNumberWithoutTrailingZeroes(1.2345, 3)** returns 1.234** Note that since this treats the value passed to it as a floating point* number, it will have counterintuitive results in some cases. For instance,** roundFloatNumberWithoutTrailingZeroes(0.015, 2)** gives 0.01 where 0.02 might be expected. For an explanation of why, see* http://stackoverflow.com/a/38676273/1709587. You may want to consider using the* roundStringNumberWithoutTrailingZeroes function there instead.** @param {number} num* @param {number} dp* @return {number}*/function roundFloatNumberWithoutTrailingZeroes (num, dp) {var numToFixedDp = Number(num).toFixed(dp);return Number(numToFixedDp);}
const ESPILON_RATE = 1 + Number.EPSILON ;const ESPILON_ZERO = Number.MIN_VALUE ;
function epsilonEquals( a , b ) {if ( Number.isNaN( a ) || Number.isNaN( b ) ) {return false ;}if ( a === 0 || b === 0 ) {return a <= b + EPSILON_ZERO && b <= a + EPSILON_ZERO ;}return a <= b * EPSILON_RATE && b <= a * EPSILON_RATE ;}
var x = 1.49999999999;console.log(x.toPrecision(4));console.log(x.toPrecision(3));console.log(x.toPrecision(2));
var y = Math.PI;console.log(y.toPrecision(6));console.log(y.toPrecision(5));console.log(y.toPrecision(4));
var z = 222.987654console.log(z.toPrecision(6));console.log(z.toPrecision(5));console.log(z.toPrecision(4));
function naiveRound(num, decimalPlaces = 0) {var p = Math.pow(10, decimalPlaces);return Math.round(num * p) / p;}
console.log( naiveRound(1.245, 2) ); // 1.25 correct (rounded as expected)console.log( naiveRound(1.255, 2) ); // 1.25 incorrect (should be 1.26)
// testing edge casesconsole.log( naiveRound(1.005, 2) ); // 1 incorrect (should be 1.01)console.log( naiveRound(2.175, 2) ); // 2.17 incorrect (should be 2.18)console.log( naiveRound(5.015, 2) ); // 5.01 incorrect (should be 5.02)
为了确定舍入操作是否涉及中点值,圆函数将要舍入的原始值乘以10**n,其中n是返回值中所需的小数位数,然后确定值的剩余小数部分是否大于或等于.5。这个带有浮点值的"Exact Testing for Equality"有问题,因为浮点格式的二进制表示和精度问题。这意味着略小于.5的数字的任何小数部分(由于精度损失)都不会向上舍入。
A simple drop in solution that provides accurate decimal rounding, flooring, and ceiling to a specific number of decimal places without adding a whole library. It treats floats more like decimals by fixing the binary rounding issues to avoid unexpected results: for example, floor((0.1+0.7)*10) will return the expected result 8.
Numbers are rounded to a specific number of fractional digits. Specifying a negative precision will round to any number of places to the left of the decimal point.
Rounded 18.339840000000436 to 18.34Rounded 52.48283999999984 to 52.48Rounded 57.24612000000036 to 57.25Rounded 23.068320000000142 to 23.07Rounded 7.792980000000398 to 7.79Rounded 31.54157999999981 to 31.54Rounded 36.79686000000004 to 36.8Rounded 34.723080000000124 to 34.72Rounded 8.4375 to 8.44Rounded 15.666960000000074 to 15.67Rounded 29.531279999999924 to 29.53Rounded 8.277420000000006 to 8.28
/*** Possibility to lose precision at large numbers* @param number* @returns Number number*/var roundUpToNearestHundredth = function(number) {
// Ensure that we use high precision Numbernumber = Number(number);
// Save the original number so when we extract the Hundredth decimal place we don't bit switch or lose precisionvar numberSave = Number(number.toFixed(0));
// Remove the "integer" values off the top of the numbernumber = number - numberSave;
// Get the Hundredth decimal placesnumber *= 100;
// Ceil the decimals. Therefore .15000001 will equal .151, etc.number = Math.ceil(number);
// Put the decimals back into their correct spotnumber /= 100;
// Add the "integer" back onto the numberreturn number + numberSave;
};
console.log(roundUpToNearestHundredth(6132423.1200000000001))
In simple cases, the solution is to perform calculation on strings instead of floating point numbers, and thus avoid rounding errors completely. However, this option fails at the first non-trivial mathematical operation (including most divsions), and it is slow.
When operating on floating point numbers, the solution is to introduce a parameter which names the amount by which we are willing to deviate from the actual computation result, in order to output the psychologically expected result.
var round = function(num, digits = 2, compensateErrors = 2) {if (num < 0) {return -this.round(-num, digits, compensateErrors);}const pow = Math.pow(10, digits);return (Math.round(num * pow * (1 + compensateErrors * Number.EPSILON)) / pow);}
/* --- testing --- */
console.log("Edge cases mentioned in this thread:")var values = [ 0.015, 1.005, 5.555, 156893.145, 362.42499999999995, 1.275, 1.27499, 1.2345678e+2, 2.175, 5.015, 58.9 * 0.15 ];values.forEach((n) => {console.log(n + " -> " + round(n));console.log(-n + " -> " + round(-n));});
console.log("\nFor numbers which are so large that rounding cannot be performed anyway within computation precision, only string-based computation can help.")console.log("Standard: " + round(1e+19));console.log("Compensation = 1: " + round(1e+19, 2, 1));console.log("Effectively no compensation: " + round(1e+19, 2, 0.4));
let round= x=> ( x+0.005 - (x+0.005)%0.01 +'' ).replace(/(\...)(.*)/,'$1');
// for a case like 1.384 we need to use a regexp to get only 2 digits after the dot// and cut off machine-error (epsilon)
console.log(round(10));console.log(round(1.7777777));console.log(round(1.7747777));console.log(round(1.384));