在 JavaScript 中格式化精确到两位小数的数字
-
19-09-2019 - |
题
我有这行代码,将我的数字四舍五入到小数点后两位。但我得到这样的数字:10.8、2.4 等这些不是我对小数点后两位的想法,那么我如何改进以下内容?
Math.round(price*Math.pow(10,2))/Math.pow(10,2);
我想要 10.80、2.40 等数字。使用 jQuery 对我来说没问题。
解决方案
要使用固定点表示法格式化一个数字,您可以简单地使用 tofix 方法:
(10.8).toFixed(2); // "10.80"
var num = 2.4;
alert(num.toFixed(2)); // "2.40"
注意 toFixed()
返回字符串。
重要的: :请注意,tofixed实际上并不是圆形的,有90%的时间将返回圆形值,但在许多情况下,它实际上行不通。在您的控制台中尝试一下:
2.005.toFixed(2)
你会得到错误的答案
没有自然的方法可以在JavaScript中获得小数舍入,您将需要自己的polyfill或使用库。您可以看一下Mozilla的Polyfill https://developer.mozilla.org/en-us/docs/web/javascript/reference/global_objects/math/round
其他提示
这是一个古老的话题,但仍排名最高的Google结果,提供的解决方案共享相同的浮点小数问题。这是我使用的(非常通用的)函数, 感谢MDN:
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));
}
如我们所见,我们没有得到这些问题:
round(1.275, 2); // Returns 1.28
round(1.27499, 2); // Returns 1.27
这种通用还提供了一些很酷的东西:
round(1234.5678, -2); // Returns 1200
round(1.2345678e+2, 2); // Returns 123.46
round("123.45"); // Returns 123
现在,要回答OP的问题,必须输入:
round(10.8034, 2).toFixed(2); // Returns "10.80"
round(10.8, 2).toFixed(2); // Returns "10.80"
或者,对于更简洁的,更少的通用功能:
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);
}
您可以致电:
round2Fixed(10.8034); // Returns "10.80"
round2Fixed(10.8); // Returns "10.80"
各种示例和测试(感谢 @tj-crowder!):
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);
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;
}
<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"></script>
我通常会将其添加到我的个人库中,并在一些建议和使用@Timineutron解决方案之后,并使其适应小数长度,然后这最适合:
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的答案的解决方案:
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(他想要)。
我的最终解决方案如下:
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是有损的 - 您可以在JSFIDDLE.NET上检查它 - 这是我唯一知道如何修复的方法“ 它)。它在已经填充的数字中添加了0.001,因此添加了一个 1
三 0
S位于小数值的右侧。因此应该安全使用。
之后我添加了 .toFixed(decimal)
始终以正确的格式输出数字(带有适量的小数)。
所以就是这样。很好地使用;)
编辑:对负数的“校正”添加功能。
100%确保您获得2个小数的数字:一种方法:
(Math.round(num*100)/100).toFixed(2)
如果这会导致四舍五入错误,您可以使用以下内容,如詹姆斯在评论中所解释的那样:
(Math.round((num * 1000)/10)/100).toFixed(2)
TOFIXED(N)在小数点后提供n个长度; TopRecision(X)提供X总长度。
在下面使用此方法
// 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
如果您想固定使用该号码
result = num.toFixed(2);
我没有找到这个问题的准确解决方案,所以我创建了自己的问题:
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;
}
例子:
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
@heridev 和我在 jQuery 中创建了一个小函数。
您可以尝试下一步:
超文本标记语言
<input type="text" name="one" class="two-digits"><br>
<input type="text" name="two" class="two-digits">
jQuery
// 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
});
});
在线演示:
这是一个简单的
function roundFloat(num,dec){
var d = 1;
for (var i=0; i<dec; i++){
d += "0";
}
return Math.round(num * d) / d;
}
使用喜欢 alert(roundFloat(1.79209243929,4));
浮点值的麻烦在于,它们试图用固定量的位来表示无限量的(连续)值。因此,自然而然的是,游戏中必须有一些损失,并且您会被一些价值观咬伤。
当计算机将1.275存储为浮点值时,它实际上不会记住是1.275还是1.27499999999999993,甚至是1.2750000000000000002。这些值在四舍五入到两个小数后应该给出不同的结果,但是它们不会,因为对于计算机来说,它们看起来 完全相同的 在存储为浮点值之后,无法恢复丢失的数据。任何进一步的计算只会累积这种不精确。
因此,如果精度很重要,则必须从一开始就避免浮点值。最简单的选项是
- 用一个 专门的库
- 使用字符串存储和传递值(伴随字符串操作)
- 使用整数(例如,您可能会传递实际价值的百分之一,例如以美分而不是美元数量)
例如,当使用整数存储百分之一时,查找实际值的功能非常简单:
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));
使用串,您需要舍入,但仍然可以控制:
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));
请注意,此功能回到最近, 远离零, , 尽管 IEEE 754 建议四舍五入到最近, 与偶数联系 作为浮点操作的默认行为。这样的修改是作为读者的练习:)
绕十进制价值,然后使用 toFixed(x)
对于您的预期数字。
function parseDecimalRoundAndFixed(num,dec){
var d = Math.pow(10,dec);
return (Math.round(num * d) / d).toFixed(dec);
}
称呼
parsedecimalroundandfixed(10.800243929,4)=> 10.80 parsedecimalroundand和fixed(10.807243929,2)=> 10.81
/**
* 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行解决方案: Number((yourNumericValueHere).toFixed(2));
这就是发生的事情:
1)首先,您申请 .toFixed(2)
在您想从十进制位置的数字上。请注意,这会将值转换为字符串。因此,如果您使用的是Typescript,它将引发这样的错误:
“类型'字符串'不能分配给类型'数字'”
2)要恢复数字值或将字符串转换为数字值,只需应用 Number()
在所谓的“字符串”值上函数。
要澄清,请查看以下示例:
例子:我的数量在十进制位置高达5位,我想将其缩短到最多2个小数位。我这样做:
var price = 0.26453;
var priceRounded = Number((price).toFixed(2));
console.log('Original Price: ' + price);
console.log('Price Rounded: ' + priceRounded);
放 以下 在某些全球范围中:
Number.prototype.getDecimals = function ( decDigCount ) {
return this.toFixed(decDigCount);
}
和 然后尝试:
var a = 56.23232323;
a.getDecimals(2); // will return 56.23
更新
注意 toFixed()
只能适用于小数的数量 0-20
IE a.getDecimals(25)
可能会生成JavaScript错误,因此可以适应您可以添加一些其他检查IE
Number.prototype.getDecimals = function ( decDigCount ) {
return ( decDigCount > 20 ) ? this : this.toFixed(decDigCount);
}
Number(((Math.random() * 100) + 1).toFixed(2))
这将返回一个随机数从1到100舍入的小数点。
Number(Math.round(1.005+'e2')+'e-2'); // 1.01
这对我有用: 在JavaScript中四舍五入
通过参考使用此响应: https://stackoverflow.com/a/21029698/454827
我构建一个函数以获取动态数量的小数:
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/
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
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<div id="result"></div>
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>
下跌
function round_down(value, decPlaces) {
return Math.floor(value * Math.pow(10, decPlaces)) / Math.pow(10, decPlaces);
}
围捕
function round_up(value, decPlaces) {
return Math.ceil(value * Math.pow(10, decPlaces)) / Math.pow(10, decPlaces);
}
圆最近
function round_nearest(value, decPlaces) {
return Math.round(value * Math.pow(10, decPlaces)) / Math.pow(10, decPlaces);
}
合并 https://stackoverflow.com/a/7641824/1889449 和 https://www.kirupa.com/html5/rounding_numbers_in_javascript.htm 谢谢他们。
在这些示例中,您仍然会在数字1.005围绕数字1.005时会遇到错误。解决方案是使用诸如Math.js之类的库或此功能:
function round(value: number, decimals: number) {
return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals);
}
几个月前,我从这篇文章中收到了一些想法,但是这里没有任何答案,其他帖子/博客的答案也无法处理所有方案(例如,我们的测试人员找到了负数和一些“幸运的数字”)。最后,我们的测试人员在下面没有发现任何问题。粘贴我的代码片段:
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));
},
我也有代码评论(对不起,我已经忘记了所有详细信息)...我在这里发布答案以供将来参考:
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).
我正在解决修饰符的问题。仅支持2小数。
$(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]);
};
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
(Math.round((10.2)*100)/100).toFixed(2)
应该产生: 10.20
(Math.round((.05)*100)/100).toFixed(2)
应该产生: 0.05
(Math.round((4.04)*100)/100).toFixed(2)
应该产生: 4.04
等等
/*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.
*/
这很简单,而且与其他任何一个一样工作:
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。就像最好的!
您也可以使用 .toPrecision()
方法和一些自定义代码,无论int零件的长度如何
function glbfrmt (number, decimals, seperator) {
return typeof number !== 'number' ? number : number.toPrecision( number.toString().split(seperator)[0].length + decimals);
}
您也可以将其制作为更好的插件。
这样简单。
var rounded_value=Math.round(value * 100) / 100;
我找到了一种非常简单的方法,可以为我解决这个问题,可以使用或适应:
td[row].innerHTML = price.toPrecision(price.toFixed(decimals).length
100%工作!!!试试看
<html>
<head>
<script>
function replacePonto(){
var input = document.getElementById('qtd');
var ponto = input.value.split('.').length;
var slash = input.value.split('-').length;
if (ponto > 2)
input.value=input.value.substr(0,(input.value.length)-1);
if(slash > 2)
input.value=input.value.substr(0,(input.value.length)-1);
input.value=input.value.replace(/[^0-9.-]/,'');
if (ponto ==2)
input.value=input.value.substr(0,(input.value.indexOf('.')+3));
if(input.value == '.')
input.value = "";
}
</script>
</head>
<body>
<input type="text" id="qtd" maxlength="10" style="width:140px" onkeyup="return replacePonto()">
</body>
</html>