我想最多舍入小数点后两位,但仅在必要时才可以。
输入:
10
1.7777777
9.1
输出:
10
1.78
9.1
如何在JavaScript中执行此操作?
Number.EPSILON
。使用Math.round( num * 100 + Number.EPSILON ) / 100
。
Number.EPSILON
这里使用的原因吗?
我想最多舍入小数点后两位,但仅在必要时才可以。
输入:
10
1.7777777
9.1
输出:
10
1.78
9.1
如何在JavaScript中执行此操作?
Number.EPSILON
。使用Math.round( num * 100 + Number.EPSILON ) / 100
。
Number.EPSILON
这里使用的原因吗?
Answers:
采用 Math.round(num * 100) / 100
编辑:为了确保像1.005这样的东西正确取整,我们使用
Math.round((num + Number.EPSILON) * 100) / 100
Math.round((num + 0.00001) * 100) / 100
。尝试Math.round((1.005 + 0.00001) * 100) / 100
和Math.round((1.0049 + 0.00001) * 100) / 100
如果值是文本类型:
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 * 1000)/1000 // 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);
}
}
https://plnkr.co/edit/uau8BlS1cqbvWPCHJeOy?p=preview
注意:这不是所有人的通用解决方案。舍入算法有几种,您的实现可以有所不同,取决于您的要求。https://zh.wikipedia.org/wiki/舍入
解决方案2是避免前端计算,并从后端服务器提取舍入的值。
parseFloat(number.toFixed(decimalPlaces));
@PerLundberg
parseFloat("55.555").toFixed(2)
"55.55"
在Chrome开发者控制台中返回。
您可以使用
function roundToTwo(num) {
return +(Math.round(num + "e+2") + "e-2");
}
我在MDN上发现了这一点。他们的方法避免了提到的 1.005问题。
roundToTwo(1.005)
1.01
roundToTwo(10)
10
roundToTwo(1.7777777)
1.78
roundToTwo(9.1)
9.1
roundToTwo(1234.5678)
1234.57
+(val)
是使用的强制等效项Number(val)
。将“ e-2”连接到数字会导致需要将字符串转换回数字。
roundToTwo(1.0049999999999999)
结果为1.01(因为,不可避免1.0049999999999999 == 1.005
)。在我看来,如果您键入num = 1.005
“明显地”“应该”将获得的浮点数舍入为1.00,因为num的确切值小于1.005。当然,在我看来,字符串'1.005''显然''应该'应当四舍五入为1.01。对于这里的实际正确行为,不同的人似乎有不同的直觉,这就是为什么它很复杂的一部分。
1.0049999999999999
和之间没有数字(浮点数)1.005
,因此根据定义,它们是相同的数字。这称为脱皮切割。
1.00499 < 1.005
IS true
,1.0049999999999999 < 1.005
计算结果为false
。
MarkG的答案是正确的。这是任意小数位数的通用扩展名。
Number.prototype.round = function(places) {
return +(Math.round(this + "e+" + places) + "e-" + places);
}
用法:
var n = 1.7777;
n.round(2); // 1.78
单元测试:
it.only('should round floats to 2 places', function() {
var cases = [
{ n: 10, e: 10, p:2 },
{ n: 1.7777, e: 1.78, p:2 },
{ n: 1.005, e: 1.01, p:2 },
{ n: 1.005, e: 1, p:0 },
{ n: 1.77777, e: 1.8, p:1 }
]
cases.forEach(function(testCase) {
var r = testCase.n.round(testCase.p);
assert.equal(r, testCase.e, 'didn\'t get right number');
});
})
function round(number, decimals) { return +(Math.round(number + "e+" + decimals) + "e-" + decimals); }
(-1.005).round(2) === -1
您应该使用:
Math.round( num * 100 + Number.EPSILON ) / 100
似乎没有人知道Number.EPSILON
。
同样值得注意的是,这并不是某些人所说的JavaScript怪异之处。
这就是浮点数在计算机中的工作方式。像99%的编程语言一样,JavaScript没有自制的浮点数。它依赖于CPU / FPU。计算机使用二进制,在二进制中,没有类似的任何数字0.1
,而仅仅是二进制近似值。为什么?出于同样的原因,不能用小数写1/3,因为它的值是0.33333333 ...,且无穷三进制。
来吧Number.EPSILON
。该数字是1和双精度浮点数中存在的下一个数字之间的差。就是这样:1
和1 + 之间没有数字Number.EPSILON
。
编辑:
正如评论中所要求的,让我们澄清一件事:加法Number.EPSILON
仅在要取整的值是算术运算的结果时才相关,因为加法会吞噬一些浮点误差增量。
当值来自直接来源(例如:文字,用户输入或传感器)时,它没有用。
编辑(2019):
就像@maganap和一些人指出的那样,最好Number.EPSILON
在相乘之前添加:
Math.round( ( num + Number.EPSILON ) * 100 ) / 100
编辑(2019年12月):
最近,我使用类似于此函数的功能来比较可识别epsilon的数字:
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 ;
}
我的用例是我多年开发的断言+数据验证库。
实际上,在我使用的代码ESPILON_RATE = 1 + 4 * Number.EPSILON
and中EPSILON_ZERO = 4 * Number.MIN_VALUE
(是epsilon的四倍),因为我希望相等性检查器足够松散以累积浮点错误。
到目前为止,它对我来说看起来很完美。希望对您有所帮助。
Math.round( (num + Number.EPSILON) * 100) / 100
。我也同意这是正确四舍五入的正确方法(尽管这并非本问题中提出的确切要求)。
0.004999999999999999
是复合浮点误差的结果,而数学上正确的结果可能是0.005。如果是传感器的读数?没那么多。
Math.round(1.5)
= 2,但Math.round(-1.5)
= -1。因此,这是完全一致的。这里-1大于-2,就像-1000大于-1000.01一样。不要与更大的绝对数字相混淆。
一个可以使用.toFixed(NumberOfDecimalPlaces)
。
var str = 10.234.toFixed(2); // => '10.23'
var number = Number(str); // => 10.23
Number(9).toFixed(2).replace(/0+$/, '')
=>“ 9”。
这个问题很复杂。
假设我们有一个函数,该函数roundTo2DP(num)
将浮点数作为参数并返回四舍五入到小数点后两位的值。这些表达式中的每个表达式的结果是什么?
roundTo2DP(0.014999999999999999)
roundTo2DP(0.0150000000000000001)
roundTo2DP(0.015)
“显而易见”的答案是,第一个示例应四舍五入到0.01(因为它比0.01更接近于0.02),而其他两个示例应四舍五入到0.02(因为0.0150000000000000001比0.02更接近于0.02,因为0.015正好介于两者之间它们,并且在数学上约定将此类数字四舍五入)。
您可能已经猜到的问题是,roundTo2DP
不可能传递这些明显的答案,因为传递给它的所有三个数字都是相同的数字。IEEE 754二进制浮点数(JavaScript使用的那种)不能完全表示大多数非整数,因此上面的所有三个数字文字都将四舍五入为附近的有效浮点数。这个数字,因为它发生,是正好
0.01499999999999999944488848768742172978818416595458984375
比0.01接近0.02。
您可以在浏览器控制台,Node shell或其他JavaScript解释器上看到所有三个数字相同。只需比较一下:
> 0.014999999999999999 === 0.0150000000000000001
true
所以当我写东西的时候,我最终m = 0.0150000000000000001
得到的确切价值m
0.01
比它更接近0.02
。但是,如果我转换m
为字符串...
> var m = 0.0150000000000000001;
> console.log(String(m));
0.015
> var m = 0.014999999999999999;
> console.log(String(m));
0.015
...我得到0.015,应该四舍五入为0.02,而且显然不是我早先所说的所有这些数字都完全相等的56位小数。那么这是什么黑魔法?
答案可以在ECMAScript规范的7.1.12.1节:适用于Number类型的ToString中找到。这里规定了将一些数字m转换为字符串的规则。关键部分是点5,其中生成一个整数s,其数字将用于m的String表示形式:
让Ñ,ķ,和s ^是整数,使得ķ ≥1,10 ķ -1 ≤ 小号 <10 ķ,为对数的值小号 ×10 ñ - ķ是米,并且ķ是尽可能小。请注意,k是s的十进制表示形式中的位数,s不能被10整除,并且s的最低有效位不一定由这些条件唯一确定。
这里的关键部分是要求“ k尽可能小”。该要求等于一个要求,给定一个Number m
,其值String(m)
必须具有尽可能少的数字,同时仍要满足the的要求Number(String(m)) === m
。由于我们已经知道这一点0.015 === 0.0150000000000000001
,所以现在很清楚为什么String(0.0150000000000000001) === '0.015'
必须为真。
当然,这些讨论都没有直接回答roundTo2DP(m)
应该返回什么。如果m
的准确值为0.01499999999999999944488848768742172978818416595458984375,但其字符串表示形式为“ 0.015”,那么当我们将其四舍五入到小数点后两位时,正确答案是什么?
没有一个正确的答案。这取决于您的用例。您可能想尊重String表示形式,并在以下情况下向上舍入:
另一方面,您可能希望尊重二进制浮点值,并在其值本质上是连续的标度时向下舍入(例如,如果它是从传感器读取的值)。
这两种方法需要不同的代码。为了尊重Number的String表示形式,我们可以(使用大量相当精巧的代码)实现自己的舍入,该舍入运算将使用您在学校时使用的相同算法,逐位直接作用于String表示形式。被教导如何四舍五入数字。下面是一个示例,该示例尊重OP要求“仅在必要时”将数字表示为小数点后2位小数点的要求;当然,您可能需要根据实际需要进行调整。
/**
* 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+37
throw new Error("num too large");
}
if (num.indexOf('.') == -1) {
// Nothing to do
return 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 stop
var 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 returning
return finalNumber.replace(/0+$/, '')
}
用法示例:
> roundStringNumberWithoutTrailingZeroes(1.6, 2)
'1.6'
> roundStringNumberWithoutTrailingZeroes(10000, 2)
'10000'
> roundStringNumberWithoutTrailingZeroes(0.015, 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes('0.015000', 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes(1, 1)
'1'
> roundStringNumberWithoutTrailingZeroes('0.015', 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes(0.01499999999999999944488848768742172978818416595458984375, 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes('0.01499999999999999944488848768742172978818416595458984375', 2)
'0.01'
上面的功能可能是您要使用的功能,以避免用户看到他们输入的数字被错误舍入。
(作为替代,您也可以尝试round10库,该库提供行为类似但功能完全不同的实现。)
但是,如果您拥有第二种数字-取自连续标度的值,而又没有理由认为小数位数较少的近似十进制表示比那些小数位数更为精确的怎么办?在这种情况下,我们不希望尊重字符串表示,因为这表示(如规格说明)已经是全面的排序; 我们不想犯这样的错误:“ 0.014999999 ... 375舍入到0.015,它舍入到0.02,所以0.014999999 ... 375舍入到0.02”。
在这里,我们可以简单地使用内置toFixed
方法。请注意,通过调用由Number()
返回的String toFixed
,我们得到一个Number,其String表示形式没有尾随零(这要归功于JavaScript对该Number的String表示形式的计算方式,此答案前面已进行了讨论)。
/**
* 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);
}
roundStringNumberWithoutTrailingZeroes(362.42499999999995, 2)
。预期结果(如PHP echo round(362.42499999999995, 2)
)362.43
。实际结果:362.42
round
给出362.43。从直觉上看这是错误的,因为362.42499999999995小于362.425(在数学和代码362.42499999999995 < 362.425
上均是如此-在JS和PHP中均是如此)。自以来,PHP的答案也没有最小化原始浮点数和舍入浮点数之间的距离362.43 - 362.42499999999995 > 362.42499999999995 - 362.42
。据php.net/manual/en/function.round.php,PHP的round
遵循C99标准; 我将不得不冒险进入C的领域,以了解发生了什么。
考虑.toFixed()
和.toPrecision()
:
精确的舍入方法。资料来源:Mozilla
(function(){
/**
* Decimal adjustment of a number.
*
* @param {String} type The type of adjustment.
* @param {Number} value The number.
* @param {Integer} exp The exponent (the 10 logarithm of the adjustment base).
* @returns {Number} The adjusted value.
*/
function decimalAdjust(type, value, exp) {
// If the exp is undefined or zero...
if (typeof exp === 'undefined' || +exp === 0) {
return Math[type](value);
}
value = +value;
exp = +exp;
// If the value is not a number or the exp is not an integer...
if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) {
return NaN;
}
// Shift
value = value.toString().split('e');
value = Math[type](+(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));
}
// Decimal round
if (!Math.round10) {
Math.round10 = function(value, exp) {
return decimalAdjust('round', value, exp);
};
}
// Decimal floor
if (!Math.floor10) {
Math.floor10 = function(value, exp) {
return decimalAdjust('floor', value, exp);
};
}
// Decimal ceil
if (!Math.ceil10) {
Math.ceil10 = function(value, exp) {
return decimalAdjust('ceil', value, exp);
};
}
})();
例子:
// Round
Math.round10(55.55, -1); // 55.6
Math.round10(55.549, -1); // 55.5
Math.round10(55, 1); // 60
Math.round10(54.9, 1); // 50
Math.round10(-55.55, -1); // -55.5
Math.round10(-55.551, -1); // -55.6
Math.round10(-55, 1); // -50
Math.round10(-55.1, 1); // -60
Math.round10(1.005, -2); // 1.01 -- compare this with Math.round(1.005*100)/100 above
// Floor
Math.floor10(55.59, -1); // 55.5
Math.floor10(59, 1); // 50
Math.floor10(-55.51, -1); // -55.6
Math.floor10(-51, 1); // -60
// Ceil
Math.ceil10(55.51, -1); // 55.6
Math.ceil10(51, 1); // 60
Math.ceil10(-55.59, -1); // -55.5
Math.ceil10(-59, 1); // -50
Math.round10(3544.5249, -2)
返回3544.52而不是3544.53
3544.5249
小数点后两位最接近的近似值是3544.52
(误差= 0.0049)。如果为3544.53
,则误差为0.0051。您正在进行连续的舍入,即Math.round10(Math.round10(3544.5249,-3),-2),这会产生较大的舍入误差,因此不理想。
number += 0.00011
Math.round10( Math.round10(3544.5249, -3) , -2)
这里没有找到正确的答案。@stinkycheeseman要求四舍五入,你们都四舍五入了数字。
要向上舍入,请使用以下命令:
Math.ceil(num * 100)/100;
Math.ceil(1.1 * 100)/100;
-它返回1.11
,因为1.1 * 100是110.00000000000001
根据全新的现代浏览器Firefox,Chrome,Safari和Opera ... IE仍旧认为的1.1*100=1100
。
Math.ceil(num.toFixed(4) * 100) / 100
Math.ceil((1.1).toFixed(4) * 100) / 100
也将1.11
在Firefox中返回,现代浏览器的问题/错误与乘法有关,人们应该了解它(例如,我当时从事过彩票游戏)。
这是一种简单的方法:
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);
}
+(10).toFixed(2); // = 10
+(10.12345).toFixed(2); // = 10.12
(10).toFixed(2); // = 10.00
(10.12345).toFixed(2); // = 10.12
+(0.015).toFixed(2) == 0.01
。
对我来说Math.round()没有给出正确的答案。我发现toFixed(2)效果更好。以下是这两个示例:
console.log(Math.round(43000 / 80000) * 100); // wrong answer
console.log(((43000 / 80000) * 100).toFixed(2)); // correct answer
1.005
。(1.005).toFixed(2)
仍然导致1.00
。
2017
只使用本机代码.toFixed()
number = 1.2345;
number.toFixed(2) // "1.23"
如果您需要严格要求并在需要时添加数字,则可以使用 replace
number = 1; // "1"
number.toFixed(5).replace(/\.?0*$/g,'');
toFixed
提出答案的几年之前提出了多个答案,而且还不能满足问题中“仅在必要时”的条件;(1).toFixed(2)
给出"1.00"
要求者的位置"1"
。
试试这个轻量级的解决方案:
function round(x, digits){
return parseFloat(x.toFixed(digits))
}
round(1.222, 2) ;
// 1.22
round(1.222, 10) ;
// 1.222
.toFixed()
反正只允许数字。
round(1.005, 2)
查看1
而不是的结果1.01
。
round(0.995, 2) => 0.99
; round(1.006, 2) => 1.01
; round(1.005, 2) => 1
有两种方法可以做到这一点。对于像我这样的人,Lodash的变体
function round(number, precision) {
var pair = (number + 'e').split('e')
var value = Math.round(pair[0] + 'e' + (+pair[1] + precision))
pair = (value + 'e').split('e')
return +(pair[0] + 'e' + (+pair[1] - precision))
}
用法:
round(0.015, 2) // 0.02
round(1.005, 2) // 1.01
如果您的项目使用jQuery或lodash,您还可以round
在库中找到合适的方法。
我删除了变体n.toFixed(2)
,因为它不正确。谢谢@ avalanche1
Number.toFixed()
将返回一个字符串,但前面带有一个加号,JS解释器会将字符串转换为数字。这是语法糖。
alert((+1234).toFixed(2))
显示“ 1234.00”。
alert(+1234.toFixed(2))
抛出SyntaxError: identifier starts immediately after numeric literal
。我坚持第一种选择。
362.42499999999995
。预期结果(如PHP echo round(362.42499999999995, 2)
)362.43
。实际结果:362.42
如果使用lodash库,则可以使用lodash的round方法,如下所示。
_.round(number, precision)
例如:
_.round(1.7777777, 2) = 1.78
从ES6开始,有一种“正确”的方法(没有覆盖静态变量和创建解决方法)通过使用toPrecision来执行此操作
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.987654
console.log(z.toPrecision(6));
console.log(z.toPrecision(5));
console.log(z.toPrecision(4));
那么你就可以,parseFloat
并且零将“消失”。
console.log(parseFloat((1.4999).toPrecision(3)));
console.log(parseFloat((1.005).toPrecision(3)));
console.log(parseFloat((1.0051).toPrecision(3)));
但是,它不能解决“ 1.005舍入问题”,因为它是浮点数处理方式所固有的。
console.log(1.005 - 0.005);
如果您对图书馆开放,可以使用bignumber.js
console.log(1.005 - 0.005);
console.log(new BigNumber(1.005).minus(0.005));
console.log(new BigNumber(1.005).round(4));
console.log(new BigNumber(1.005).round(3));
console.log(new BigNumber(1.005).round(2));
console.log(new BigNumber(1.005).round(1));
<script src="https://cdnjs.cloudflare.com/ajax/libs/bignumber.js/2.3.0/bignumber.min.js"></script>
(1.005).toPrecision(3)
仍然返回1.00
而不是1.01
实际返回。
toPrecision
返回更改所需输出类型的字符串。
.toPrecision
方法的缺陷,它是浮点数的特殊性(JS中的数字是)— try 1.005 - 0.005
,它将返回0.9999999999999999
。
(1).toPrecision(3)
返回“ 1.00”,但1
在这种情况下发问者希望拥有。
toPrecision
格式,不是后者,也不是OP的问题的答案,尽管乍一看似乎很相关,但却有很多错误。参见en.wikipedia.org/wiki/Significant_figures。例如Number(123.4).toPrecision(2)
return "1.2e+2"
和Number(12.345).toPrecision(2)
return "12"
。我也同意@adamduren的观点,即它返回一个不希望的字符串(这不是一个大问题,但不理想)。
MarkG和Lavamantis提供了比已被接受的解决方案更好的解决方案。可惜他们没有更多的投票!
这是我用来解决浮点小数问题的函数 基于MDN。它比Lavamantis的解决方案更为通用(但不够简洁):
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(10.8034, 2); // Returns 10.8
round(1.275, 2); // Returns 1.28
round(1.27499, 2); // Returns 1.27
round(1.2345678e+2, 2); // Returns 123.46
与Lavamantis的解决方案相比,我们可以做...
round(1234.5678, -2); // Returns 1200
round("123.45"); // Returns 123
这可以帮助您:
var result = Math.round(input*100)/100;
有关更多信息,您可以查看此链接
最简单的方法是使用toFixed,然后使用Number函数去除尾随零:
const number = 15.5;
Number(number.toFixed(2)); // 15.5
const number = 1.7777777;
Number(number.toFixed(2)); // 1.78
15.00
?JS中的数字不存储小数位,并且任何显示都会自动截断多余的小数位(末尾任何零)。
var roundUpto = function(number, upto){
return Number(number.toFixed(upto));
}
roundUpto(0.1464676, 2);
toFixed(2)
这里2是我们要舍入该数字的位数。
使用类似“ parseFloat(parseFloat(value).toFixed(2))”的内容
parseFloat(parseFloat("1.7777777").toFixed(2))-->1.78
parseFloat(parseFloat("10").toFixed(2))-->10
parseFloat(parseFloat("9.1").toFixed(2))-->9.1
仅在必要时实现这种舍入的一种方法是使用Number.prototype.toLocaleString():
myNumber.toLocaleString('en', {maximumFractionDigits:2, useGrouping:false})
这将完全提供您期望的输出,但以字符串形式提供。如果这不是您期望的数据类型,您仍然可以将其转换回数字。
toLocaleString
。
在经过所有可能的方式的各种迭代以达到真正准确的十进制舍入精度之后,很明显,最准确,最有效的解决方案是使用Number.EPSILON。这为浮点数学精度问题提供了一个真正的数学解决方案。可以很容易地对其进行填充,如下所示:https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/EPSILON以支持所有剩余的IE用户(那么也许我们再次应该停止这样做)。
改编自此处提供的解决方案:https : //stackoverflow.com/a/48850944/6910392
一种简单的解决方案,可提供准确的十进制舍入,下限和上限,并带有可选的precision变量,而无需添加整个库。
更新:正如Sergey在评论中指出的那样,值得指出的是这种(或任何一种)方法的局限性。在使用数字如0.014999999999999999的情况下,您仍然会遇到误差,这是由于达到浮点值存储的精度限制的绝对边缘而导致的。没有数学或其他解决方案可用于解决此问题,因为该值本身会立即评估为0.015。您可以通过在控制台中自行调用该值来确认这一点。由于此限制,甚至不可能使用字符串操作来减小此值,因为其字符串表示形式只是“ 0.015”。任何解决此问题的解决方案都需要在逻辑上应用于数据源,然后再将值接受到脚本中,
var DecimalPrecision = (function(){
if (Number.EPSILON === undefined) {
Number.EPSILON = Math.pow(2, -52);
}
this.round = function(n, p=2){
let r = 0.5 * Number.EPSILON * n;
let o = 1; while(p-- > 0) o *= 10;
if(n < 0)
o *= -1;
return Math.round((n + r) * o) / o;
}
this.ceil = function(n, p=2){
let r = 0.5 * Number.EPSILON * n;
let o = 1; while(p-- > 0) o *= 10;
if(n < 0)
o *= -1;
return Math.ceil((n + r) * o) / o;
}
this.floor = function(n, p=2){
let r = 0.5 * Number.EPSILON * n;
let o = 1; while(p-- > 0) o *= 10;
if(n < 0)
o *= -1;
return Math.floor((n + r) * o) / o;
}
return this;
})();
console.log(DecimalPrecision.round(1.005));
console.log(DecimalPrecision.ceil(1.005));
console.log(DecimalPrecision.floor(1.005));
console.log(DecimalPrecision.round(1.0049999));
console.log(DecimalPrecision.ceil(1.0049999));
console.log(DecimalPrecision.floor(1.0049999));
console.log(DecimalPrecision.round(2.175495134384,7));
console.log(DecimalPrecision.round(2.1753543549,8));
console.log(DecimalPrecision.round(2.1755465135353,4));
这是最简单,更优雅的解决方案(而且我是世界上最好的;):
function roundToX(num, X) {
return +(Math.round(num + "e+"+X) + "e-"+X);
}
//roundToX(66.66666666,2) => 66.67
//roundToX(10,2) => 10
//roundToX(10.904,2) => 10.9
E
符号表示的接受答案以接受参数的好方法。
roundToX(362.42499999999995, 2)
。预期结果(如PHP echo round(362.42499999999995, 2)
)362.43
。实际结果:362.42