Formatting a number with exactly two decimals in JavaScript
我有这行代码,它将我的数字舍入到小数点后两位。但是我得到了这样的数字:10.8,2.4,等等。这些不是我对两个小数位的想法,所以我如何改进下面的内容?
1 | Math.round(price*Math.pow(10,2))/Math.pow(10,2); |
我想要10.80、2.40等数字。使用jquery对我来说很好。
要使用定点表示法格式化数字,只需使用to fixed方法:
1 2 3 4 | (10.8).toFixed(2); //"10.80" var num = 2.4; alert(num.toFixed(2)); //"2.40" |
注意,
重要提示:请注意,tofixed实际上不舍入,90%的时间,它将返回舍入值,但在许多情况下,它实际上不起作用。在控制台中尝试此操作:
你会得到错误的答案
在javascript中没有自然的方法获得小数舍入,您将需要自己的polyfill或使用库。您可以查看此https://developer.mozilla.org/en-us/docs/web/javascript/reference/global_objects/math/round的Mozilla polyfill
这是一个古老的话题,但仍然是排名第一的谷歌搜索结果,并且提供的解决方案共享相同的浮点小数问题。以下是我使用的(非常通用的)函数,这归功于MDN:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | function round(value, exp) { if (typeof exp === 'undefined' || +exp === 0) return Math.round(value); value = +value; exp = +exp; if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) return NaN; // Shift value = value.toString().split('e'); value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp))); // Shift back value = value.toString().split('e'); return +(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp)); } |
正如我们所看到的,我们不知道这些问题:
1 2 | round(1.275, 2); // Returns 1.28 round(1.27499, 2); // Returns 1.27 |
这种通用性还提供了一些很酷的东西:
1 2 3 | round(1234.5678, -2); // Returns 1200 round(1.2345678e+2, 2); // Returns 123.46 round("123.45"); // Returns 123 |
现在,要回答OP的问题,必须键入:
1 2 | round(10.8034, 2).toFixed(2); // Returns"10.80" round(10.8, 2).toFixed(2); // Returns"10.80" |
或者,对于更简洁、更不一般的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | function round2Fixed(value) { value = +value; if (isNaN(value)) return NaN; // Shift value = value.toString().split('e'); value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + 2) : 2))); // Shift back value = value.toString().split('e'); return (+(value[0] + 'e' + (value[1] ? (+value[1] - 2) : -2))).toFixed(2); } |
您可以通过以下方式调用它:
1 2 | round2Fixed(10.8034); // Returns"10.80" round2Fixed(10.8); // Returns"10.80" |
各种示例和测试(感谢@t-j-crowder!):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | function round(value, exp) { if (typeof exp === 'undefined' || +exp === 0) return Math.round(value); value = +value; exp = +exp; if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) return NaN; // Shift value = value.toString().split('e'); value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp))); // Shift back value = value.toString().split('e'); return +(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp)); } function naive(value, exp) { if (!exp) { return Math.round(value); } var pow = Math.pow(10, exp); return Math.round(value * pow) / pow; } function test(val, places) { subtest(val, places); val = typeof val ==="string" ?"-" + val : -val; subtest(val, places); } function subtest(val, places) { var placesOrZero = places || 0; var naiveResult = naive(val, places); var roundResult = round(val, places); if (placesOrZero >= 0) { naiveResult = naiveResult.toFixed(placesOrZero); roundResult = roundResult.toFixed(placesOrZero); } else { naiveResult = naiveResult.toString(); roundResult = roundResult.toString(); } $("<tr>") .append($("<td>").text(JSON.stringify(val))) .append($("<td>").text(placesOrZero)) .append($("<td>").text(naiveResult)) .append($("<td>").text(roundResult)) .appendTo("#results"); } test(0.565, 2); test(0.575, 2); test(0.585, 2); test(1.275, 2); test(1.27499, 2); test(1234.5678, -2); test(1.2345678e+2, 2); test("123.45"); test(10.8034, 2); test(10.8, 2); test(1.005, 2); test(1.0005, 2); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | table { border-collapse: collapse; } table, td, th { border: 1px solid #ddd; } td, th { padding: 4px; } th { font-weight: normal; font-family: sans-serif; } td { font-family: monospace; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 | <table> <thead> <tr> <th>Input</th> <th>Places</th> <th>Naive</th> <th>Thorough</th> </tr> </thead> <tbody id="results"> </tbody> </table> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"> |
我通常会将此添加到我的个人库中,经过一些建议和使用@timinutron解决方案,并使其适合十进制长度,然后,此解决方案最适合:
1 2 3 4 | function precise_round(num, decimals) { var t = Math.pow(10, decimals); return (Math.round((num * t) + (decimals>0?1:0)*(Math.sign(num) * (10 / Math.pow(100, decimals)))) / t).toFixed(decimals); } |
适用于报告的例外情况。
我不知道为什么我不能在以前的答案中添加评论(可能我是个完全失明的人,邓诺),但我用@miguel的答案提出了一个解决方案:
1 2 3 | function precise_round(num,decimals) { return Math.round(num*Math.pow(10, decimals)) / Math.pow(10, decimals); } |
及其两条评论(来自@bighostkim和@imre):
precise_round(1.275,2) 不返回1.28的问题precise_round(6,2) 不返回6.00(如他所愿)的问题。
我的最终解决方案如下:
1 2 3 4 | function precise_round(num,decimals) { var sign = num >= 0 ? 1 : -1; return (Math.round((num*Math.pow(10,decimals)) + (sign*0.001)) / Math.pow(10,decimals)).toFixed(decimals); } |
正如你所看到的,我必须添加一点"修正"(这不是它是什么,但因为math.round是有损的-你可以在jfiddle.net上检查它-这是我知道如何"修正"它的唯一方法)。它在已经填充的数字上加0.001,因此在十进制值的右边加一个
之后,我添加了
差不多就是这样。好好利用它;
编辑:增加了负数的"修正"功能。
一种方法是100%确保你得到一个带2个小数的数字:
1 | (Math.round(num*100)/100).toFixed(2) |
如果这导致舍入错误,您可以使用以下内容,正如詹姆斯在他的评论中所解释的那样:
1 | (Math.round((num * 1000)/10)/100).toFixed(2) |
toFixed(n) provides n length after the decimal point; toPrecision(x)
provides x total length.
使用下面的方法
1 2 3 4 | // Example: toPrecision(4) when the number has 7 digits (3 before, 4 after) // It will round to the tenths place num = 500.2349; result = num.toPrecision(4); // result will equal 500.2 |
如果你想固定电话号码的话
1 | result = num.toFixed(2); |
我没有找到这个问题的准确解决方案,因此我创建了自己的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | function inprecise_round(value, decPlaces) { return Math.round(value*Math.pow(10,decPlaces))/Math.pow(10,decPlaces); } function precise_round(value, decPlaces){ var val = value * Math.pow(10, decPlaces); var fraction = (Math.round((val-parseInt(val))*10)/10); //this line is for consistency with .NET Decimal.Round behavior // -342.055 => -342.06 if(fraction == -0.5) fraction = -0.6; val = Math.round(parseInt(val) + fraction) / Math.pow(10, decPlaces); return val; } |
实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | function inprecise_round(value, decPlaces) { return Math.round(value * Math.pow(10, decPlaces)) / Math.pow(10, decPlaces); } function precise_round(value, decPlaces) { var val = value * Math.pow(10, decPlaces); var fraction = (Math.round((val - parseInt(val)) * 10) / 10); //this line is for consistency with .NET Decimal.Round behavior // -342.055 => -342.06 if (fraction == -0.5) fraction = -0.6; val = Math.round(parseInt(val) + fraction) / Math.pow(10, decPlaces); return val; } // This may produce different results depending on the browser environment console.log("342.055.toFixed(2) :", 342.055.toFixed(2)); // 342.06 on Chrome & IE10 console.log("inprecise_round(342.055, 2):", inprecise_round(342.055, 2)); // 342.05 console.log("precise_round(342.055, 2) :", precise_round(342.055, 2)); // 342.06 console.log("precise_round(-342.055, 2) :", precise_round(-342.055, 2)); // -342.06 console.log("inprecise_round(0.565, 2) :", inprecise_round(0.565, 2)); // 0.56 console.log("precise_round(0.565, 2) :", precise_round(0.565, 2)); // 0.57 |
这是一个简单的
1 2 3 4 5 6 7 | function roundFloat(num,dec){ var d = 1; for (var i=0; i<dec; i++){ d +="0"; } return Math.round(num * d) / d; } |
像
杰西德
@我和赫里德夫在jquery中创建了一个小函数。
您可以尝试下一步:
HTML
1 2 | <input type="text" name="one" class="two-digits"> <input type="text" name="two" class="two-digits">? |
JQuery
1 2 3 4 5 6 7 8 9 10 11 12 | // apply the two-digits behaviour to elements with 'two-digits' as their class $( function() { $('.two-digits').keyup(function(){ if($(this).val().indexOf('.')!=-1){ if($(this).val().split(".")[1].length > 2){ if( isNaN( parseFloat( this.value ) ) ) return; this.value = parseFloat(this.value).toFixed(2); } } return this; //for chaining }); }); |
?在线演示:
http://jsfiddle.net/c4wqn/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | /** * MidpointRounding away from zero ('arithmetic' rounding) * Uses a half-epsilon for correction. (This offsets IEEE-754 * half-to-even rounding that was applied at the edge cases). */ function RoundCorrect(num, precision = 2) { // half epsilon to correct edge cases. var c = 0.5 * Number.EPSILON * num; // var p = Math.pow(10, precision); //slow var p = 1; while (precision--> 0) p *= 10; if (num < 0) p *= -1; return Math.round((num + c) * p) / p; } // testing some +ve edge cases console.log(RoundCorrect(1.005, 2)); // 1.01 correct console.log(RoundCorrect(2.175, 2)); // 2.18 correct console.log(RoundCorrect(5.015, 2)); // 5.02 correct // testing some -ve edge cases console.log(RoundCorrect(-1.005, 2)); // -1.01 correct console.log(RoundCorrect(-2.175, 2)); // -2.18 correct console.log(RoundCorrect(-5.015, 2)); // -5.02 correct |
浮点值的问题在于,它们试图用固定的位数表示无限量(连续)的值。所以自然,游戏中一定会有一些损失,你会被一些价值观所咬。
当计算机将1.275存储为浮点值时,它实际上不会记得是1.275还是1.27499999999993,甚至是1.275000000000002。这些值在四舍五入到两位小数后会给出不同的结果,但不会,因为对于计算机来说,它们在存储为浮点值后看起来完全相同,而且无法恢复丢失的数据。任何进一步的计算只会积累这种不精确性。
因此,如果精度很重要,则必须从一开始就避免浮点值。最简单的选择是
- 使用专门的图书馆
- 使用字符串存储和传递值(伴随字符串操作)
- 使用整数(例如,您可以传递实际值的百分之一,例如以美分表示的金额而不是以美元表示的金额)
例如,当使用整数存储百分位数时,查找实际值的函数非常简单:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | function descale(num, decimals) { var hasMinus = num < 0; var numString = Math.abs(num).toString(); var precedingZeroes = ''; for (var i = numString.length; i <= decimals; i++) { precedingZeroes += '0'; } numString = precedingZeroes + numString; return (hasMinus ? '-' : '') + numString.substr(0, numString.length-decimals) + '.' + numString.substr(numString.length-decimals); } alert(descale(127, 2)); |
使用字符串,您需要舍入,但它仍然是可管理的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | function precise_round(num, decimals) { var parts = num.split('.'); var hasMinus = parts.length > 0 && parts[0].length > 0 && parts[0].charAt(0) == '-'; var integralPart = parts.length == 0 ? '0' : (hasMinus ? parts[0].substr(1) : parts[0]); var decimalPart = parts.length > 1 ? parts[1] : ''; if (decimalPart.length > decimals) { var roundOffNumber = decimalPart.charAt(decimals); decimalPart = decimalPart.substr(0, decimals); if ('56789'.indexOf(roundOffNumber) > -1) { var numbers = integralPart + decimalPart; var i = numbers.length; var trailingZeroes = ''; var justOneAndTrailingZeroes = true; do { i--; var roundedNumber = '1234567890'.charAt(parseInt(numbers.charAt(i))); if (roundedNumber === '0') { trailingZeroes += '0'; } else { numbers = numbers.substr(0, i) + roundedNumber + trailingZeroes; justOneAndTrailingZeroes = false; break; } } while (i > 0); if (justOneAndTrailingZeroes) { numbers = '1' + trailingZeroes; } integralPart = numbers.substr(0, numbers.length - decimals); decimalPart = numbers.substr(numbers.length - decimals); } } else { for (var i = decimalPart.length; i < decimals; i++) { decimalPart += '0'; } } return (hasMinus ? '-' : '') + integralPart + (decimals > 0 ? '.' + decimalPart : ''); } alert(precise_round('1.275', 2)); alert(precise_round('1.27499999999999993', 2)); |
请注意,此函数舍入为最接近的,远离零,而IEEE754建议舍入为最接近的,即使是浮点操作的默认行为也与之相关。这些修改留给读者作为练习:)
这是我的一线解决方案:
以下是发生的事情:
1)首先,将
"类型'string'不可分配给类型'number'"
2)要返回数值或将字符串转换为数值,只需对该所谓的"字符串"值应用
如需澄清,请参阅以下示例:
例子:我有一个在小数点后5位的数字,我想把它缩短到小数点后2位。我喜欢这样做:
1 2 3 4 | var price = 0.26453; var priceRounded = Number((price).toFixed(2)); console.log('Original Price: ' + price); console.log('Price Rounded: ' + priceRounded); |
四舍五入您的十进制值,然后使用
1 2 3 4 | function parseDecimalRoundAndFixed(num,dec){ var d = Math.pow(10,dec); return (Math.round(num * d) / d).toFixed(dec); } |
呼叫
ParseDecimalRoundAndFixed(10.800243929,4)=>10.80ParseDecimalRoundAndFixed(10.807243929,2)=>10.81
圆圆向下
1 2 3 | function round_down(value, decPlaces) { return Math.floor(value * Math.pow(10, decPlaces)) / Math.pow(10, decPlaces); } |
围捕
1 2 3 | function round_up(value, decPlaces) { return Math.ceil(value * Math.pow(10, decPlaces)) / Math.pow(10, decPlaces); } |
圆最近
1 2 3 | function round_nearest(value, decPlaces) { return Math.round(value * Math.pow(10, decPlaces)) / Math.pow(10, decPlaces); } |
Merged https://stackoverflow.com/a/7641824/1889449 and
https://www.kirupa.com/html5/rounding_numbers_in_javascript.htm Thanks
them.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | parse = function (data) { data = Math.round(data*Math.pow(10,2))/Math.pow(10,2); if (data != null) { var lastone = data.toString().split('').pop(); if (lastone != '.') { data = parseFloat(data); } } return data; }; $('#result').html(parse(200)); // output 200 $('#result1').html(parse(200.1)); // output 200.1 $('#result2').html(parse(200.10)); // output 200.1 $('#result3').html(parse(200.109)); // output 200.11 |
1 | <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"> |
引用此响应:https://stackoverflow.com/a/21029698/454827
我构建了一个函数来获取动态小数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | function toDec(num, dec) { if(typeof dec=='undefined' || dec<0) dec = 2; var tmp = dec + 1; for(var i=1; i<=tmp; i++) num = num * 10; num = num / 10; num = Math.round(num); for(var i=1; i<=dec; i++) num = num / 10; num = num.toFixed(dec); return num; } |
这里的工作示例:https://jsfiddle.net/wpxldulc/
1 | Number(((Math.random() * 100) + 1).toFixed(2)) |
这将返回一个从1到100的随机数,四舍五入到小数点后2位。
通过这些示例,在尝试将数字1.005四舍五入时仍然会出错,解决方案是使用math.js之类的库或此函数:
1 2 3 | function round(value: number, decimals: number) { return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals); } |
1 | Number(Math.round(1.005+'e2')+'e-2'); // 1.01 |
这对我很有用:在javascript中舍入小数
将以下内容放在一些全局范围内:
1 2 3 | Number.prototype.getDecimals = function ( decDigCount ) { return this.toFixed(decDigCount); } |
然后尝试:
1 2 | var a = 56.23232323; a.getDecimals(2); // will return 56.23 |
更新
注意,
1 2 3 | Number.prototype.getDecimals = function ( decDigCount ) { return ( decDigCount > 20 ) ? this : this.toFixed(decDigCount); } |
几个月前,我从这篇文章中得到了一些想法,但是这里的答案和其他文章/博客中的答案都不能处理所有的情况(例如,我们的测试人员发现的负数和一些"幸运数字")。最后,我们的测试人员在下面的方法中没有发现任何问题。粘贴我的代码片段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | fixPrecision: function (value) { var me = this, nan = isNaN(value), precision = me.decimalPrecision; if (nan || !value) { return nan ? '' : value; } else if (!me.allowDecimals || precision <= 0) { precision = 0; } //[1] //return parseFloat(Ext.Number.toFixed(parseFloat(value), precision)); precision = precision || 0; var negMultiplier = value < 0 ? -1 : 1; //[2] var numWithExp = parseFloat(value +"e" + precision); var roundedNum = parseFloat(Math.round(Math.abs(numWithExp)) + 'e-' + precision) * negMultiplier; return parseFloat(roundedNum.toFixed(precision)); }, |
我还有代码注释(抱歉,我已经忘记了所有细节)…我将在这里发布我的答案以备将来参考:
1 2 3 4 | 9.995 * 100 = 999.4999999999999 Whereas 9.995e2 = 999.5 This discrepancy causes Math.round(9.995 * 100) = 999 instead of 1000. Use e notation instead of multiplying /dividing by Math.Pow(10,precision). |
很简单。
1 | var rounded_value=Math.round(value * 100) / 100; |
我来解决这个问题,修饰符。只支持2位小数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | $(function(){ //input number only. convertNumberFloatZero(22); // output : 22.00 convertNumberFloatZero(22.5); // output : 22.50 convertNumberFloatZero(22.55); // output : 22.55 convertNumberFloatZero(22.556); // output : 22.56 convertNumberFloatZero(22.555); // output : 22.55 convertNumberFloatZero(22.5541); // output : 22.54 convertNumberFloatZero(22222.5541); // output : 22,222.54 function convertNumberFloatZero(number){ if(!$.isNumeric(number)){ return 'NaN'; } var numberFloat = number.toFixed(3); var splitNumber = numberFloat.split("."); var cNumberFloat = number.toFixed(2); var cNsplitNumber = cNumberFloat.split("."); var lastChar = splitNumber[1].substr(splitNumber[1].length - 1); if(lastChar > 0 && lastChar < 5){ cNsplitNumber[1]--; } return Number(splitNumber[0]).toLocaleString('en').concat('.').concat(cNsplitNumber[1]); }; }); |
1 | <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"> |
我找到了一个非常简单的方法来解决这个问题,并且可以使用或修改:
1 | td[row].innerHTML = price.toPrecision(price.toFixed(decimals).length |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /*Due to all told stuff. You may do 2 things for different purposes: When showing/printing stuff use this in your alert/innerHtml= contents: YourRebelNumber.toFixed(2)*/ var aNumber=9242.16; var YourRebelNumber=aNumber-9000; alert(YourRebelNumber); alert(YourRebelNumber.toFixed(2)); /*and when comparing use: Number(YourRebelNumber.toFixed(2))*/ if(YourRebelNumber==242.16)alert("Not Rounded"); if(Number(YourRebelNumber.toFixed(2))==242.16)alert("Rounded"); /*Number will behave as you want in that moment. After that, it'll return to its defiance. */ |
这是非常简单的,并且和其他任何一种方法一样有效:
1 2 3 4 5 | function parseNumber(val, decimalPlaces) { if (decimalPlaces == null) decimalPlaces = 0 var ret = Number(val).toFixed(decimalPlaces) return Number(ret) } |
由于tofixed()只能对数字调用,不幸的是,它返回一个字符串,这将在两个方向上为您进行所有的解析。你可以传递一个字符串或一个数字,每次都会得到一个数字!调用parseNumber(1.49)将得到1,parseNumber(1.49,2)将得到1.50。就像他们中最好的!
您也可以使用
1 2 3 | function glbfrmt (number, decimals, seperator) { return typeof number !== 'number' ? number : number.toPrecision( number.toString().split(seperator)[0].length + decimals); } |
你也可以把它作为一个插件来更好地使用。
1 | (Math.round((10.2)*100)/100).toFixed(2) |
这应该会产生:
1 | (Math.round((.05)*100)/100).toFixed(2) |
这应该会产生:
1 | (Math.round((4.04)*100)/100).toFixed(2) |
这应该会产生:
等。
100%工作!!!!试试看
28