我想最多四舍五入两位小数,但只有在必要时。
输入:
10
1.7777777
9.1
输出:
10
1.78
9.1
如何在JavaScript中执行此操作?
我想最多四舍五入两位小数,但只有在必要时。
输入:
10
1.7777777
9.1
输出:
10
1.78
9.1
如何在JavaScript中执行此操作?
当前回答
这项看似简单的任务面临的最大挑战是,我们希望它能够产生心理预期的结果,即使输入包含最小的舍入误差(更不用说计算中会出现的误差)。如果我们知道实际结果正好是1.005,那么我们预计舍入到两位数会得到1.01,即使1.005是一个带有大量舍入误差的大型计算的结果。
当处理floor()而不是round()时,问题变得更加明显。例如,当删除33.3点后面的最后两位数字后的所有内容时,我们肯定不会期望得到33.29,但这就是结果:
console.log(数学楼层(33.3*100)/100)
在简单的情况下,解决方案是对字符串而不是浮点数执行计算,从而完全避免舍入错误。然而,这个选项在第一次非平凡的数学运算(包括大多数除法运算)时失败,而且速度很慢。
当对浮点数进行操作时,解决方案是引入一个参数,该参数指定我们愿意偏离实际计算结果的量,以便输出心理预期的结果。
var round=函数(num,数字=2,compensateErrors=2){如果(num<0){return this.round(-num,数字,compensateErrors);}const pow=数学.pow(10,数字);return(数学舍入(num*pow*(1+compensateErrors*Number.EPSILON))/pow);}/*---测试---*/console.log(“本线程中提到的边缘案例:”)var值=[0.015,1.005,5.555,156893.145,362.42499999999995,1.275,1.277499,1.2345678e+2,2.175,5.015,58.9*0.15];值。对于每个((n)=>{console.log(n+“->”+圆(n));console.log(-n+“->”+圆形(-n));});console.log(“\n对于太大以至于无法在计算精度范围内执行舍入的数字,只有基于字符串的计算才有帮助。”)console.log(“标准:”+圆形(1e+19));console.log(“补偿=1:”+圆(1e+19,2,1));console.log(“有效无补偿:”+round(1e+19,2,0.4));
注意:Internet Explorer不知道Number.EPSILON。如果您仍然需要支持它,那么您可以使用垫片,或者自己定义特定浏览器系列的常量。
其他回答
另一个简单的解决方案(无需编写任何函数)可以使用toFixed(),然后再次转换为float:
例如:
var objNumber = 1201203.1256546456;
objNumber = parseFloat(objNumber.toFixed(2))
这里有一个简单的方法:
Math.round(value * 100) / 100
不过,您可能需要继续创建一个单独的函数来为您执行此操作:
function roundToTwo(value) {
return(Math.round(value * 100) / 100);
}
然后,只需传入值。
通过添加第二个参数,可以将其增强为任意小数位数。
function myRound(value, places) {
var multiplier = Math.pow(10, places);
return (Math.round(value * multiplier) / multiplier);
}
我为自己编写了以下一组函数。也许这对你也有帮助。
function float_exponent(number) {
exponent = 1;
while (number < 1.0) {
exponent += 1
number *= 10
}
return exponent;
}
function format_float(number, extra_precision) {
precision = float_exponent(number) + (extra_precision || 0)
return number.toFixed(precision).split(/\.?0+$/)[0]
}
用法:
format_float(1.01); // 1
format_float(1.06); // 1.1
format_float(0.126); // 0.13
format_float(0.000189); // 0.00019
对于您的情况:
format_float(10, 1); // 10
format_float(9.1, 1); // 9.1
format_float(1.77777, 1); // 1.78
使用此函数Number(x).toFixed(2);
如果值是文本类型:
parseFloat("123.456").toFixed(2);
如果值是数字:
var numb = 123.23454;
numb = numb.toFixed(2);
有一个缺点,像1.5这样的值将给出“1.50”作为输出。@minitech建议的修复方法:
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.
Math.round似乎是一个更好的解决方案。但事实并非如此!在某些情况下,它不会正确舍入:
Math.round(1.005 * 100)/100 // Returns 1 instead of expected 1.01!
toFixed()在某些情况下也不会正确舍入(在Chrome v.55.0.2883.87中测试)!
示例:
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.
我想,这是因为1.555实际上就像是幕后的浮球1.55499994。
解决方案1是使用具有所需舍入算法的脚本,例如:
function roundNumber(num, scale) {
if(!("" + num).includes("e")) {
return +(Math.round(num + "e+" + scale) + "e-" + scale);
} else {
var arr = ("" + num).split("e");
var sig = ""
if(+arr[1] + scale > 0) {
sig = "+";
}
return +(Math.round(+arr[0] + "e" + sig + (+arr[1] + scale)) + "e-" + scale);
}
}
它也在Plunker。
注意:这并不是每个人都能通用的解决方案。有几种不同的舍入算法。您的实现可能不同,这取决于您的需求。请参见舍入。
解决方案2是避免前端计算,并从后端服务器提取舍入值。
另一种可能的解决方案,也不是防弹的。
Math.round((num + Number.EPSILON) * 100) / 100
在某些情况下,当您舍入像1.3549999999999998这样的数字时,它将返回错误的结果。它应该是1.35,但结果是1.36。