Javascript 中的负数四舍五入

Rounding of negative numbers in Javascript

我们在 JavaScript 中遇到了 Math.round() 的问题。问题是此函数不能正确舍入负数。例如:

1.5 ~= 2

0.5 ~= 1

-0.5 ~= 0 // 错误

-1.5 ~= -1 // 错误

根据算术舍入,这是不正确的。 -0.5 的正确数字应该是 -1,-1.5 应该是 -2。

是否有任何标准方法可以正确舍入 Javascript 中的负数?

应用Math.round after converting to a positive number and finally roll back the sign. Where you can use Math.sign method to get the sign from the number and Math.abs得到数字的绝对值。

console.log(
  Math.sign(num) * Math.round(Math.sign(num) * num),
  // or
  Math.sign(num) * Math.round(Math.abs(num))
)

var nums = [-0.5, 1.5, 3, 3.6, -4.8, -1.3];

nums.forEach(function(num) {
  console.log(
    Math.sign(num) * Math.round(Math.sign(num) * num),
    Math.sign(num) * Math.round(Math.abs(num))
  )
});

您可以保存标志并稍后在 ES5 中应用;

function round(v) {
    return (v >= 0 || -1) * Math.round(Math.abs(v));
}

console.log(round(1.5));  //  2
console.log(round(0.5));  //  1
console.log(round(-1.5)); // -2
console.log(round(-0.5)); // -1

var r = (Math.random() * 200) - 100;

在不使用数学库的情况下纯粹评估结果如何?例如,通过使用三元运算符,您可以优雅地检查负数,然后在 "rounding":

之后进行 floor
var n = r + (r < 0 ? -0.5 : 0.5) | 0;

| 0 只是 js 中的一个愚蠢的把戏 "overloads" 二元运算符(您可以使用任何二元运算符)以截断数字。

注意 这不是地板(像 Math.floor),因为 Math.floor(-3.2),例如,实际上会产生 -4


甚至可以做类似于@Balan 的回答的事情(我喜欢那个和下面的那个,但我觉得这个或三元运算符会更快一点——不过我可能错了,因为Math 库已被证明非常快):

var n = (r + Math.sign(r) / 2) | 0;

可能是最快、最优雅的方式:

var n = Math.floor(r + 0.5);

示例:

var body = document.getElementById("myTable").children[1];
var i, iMax = 100, r, tr, td;
for (i = 0; i < iMax; i++) {
    r = Math.random() * 200 - 100;
    tr = document.createElement("tr");
    td = document.createElement("td");
    td.innerHTML = r;
    tr.appendChild(td);
    td = document.createElement("td");
    td.innerHTML = (r + Math.sign(r) / 2) | 0;
    tr.appendChild(td);
    body.appendChild(tr);
}
#myTable {
    min-width: 250px;
}
<table id="myTable">
 <thead>
  <tr>
   <th>float</th>
   <th>round</th>
  </tr>
 </thead>
 <tbody>
 </tbody>
</table>

您可以尝试使用 Math.ceil(number) 对数字进行舍入,然后 - 如果 num 为负则为 1,例如

if (num < 0) {
  num = Math.ceil(num) - 1;
} else {
  num = Math.ceil(num);
}

精确舍入。
默认情况下舍入为 Int,或者如果提供了第二个参数,则舍入到小数点后的 n 位数字。
+“1”修复了 .0X5 数字的不正确舍入。

function round(num, digits=0) {
    if (!(num % 1)) return num
    return +Number(num + '1').toFixed(digits)
}

首先观察Math.round(v)定义为Math.floor(v + 0.5):

Math.round(-1.7) === -2
Math.round(-1.3) === -1
Math.floor(-1.7 + 0.5) === -2
Math.floor(-1.3 + 0.5) === -1

然后意识到 parseInt(v) 类似于 Math.floor(v),但是,它处理负数的方式不同(正是您所期望的):

Math.floor(1.7) === 1
Math.floor(-1.7) === -2
parseInt(1.7) === 1
parseInt(-1.7) === -1

所以 parseInt(v) 行为是您想要的,但您想要舍入而不是地板。为了将其应用于任何数字,我们需要为正数添加 +0.5,为负数添加 -0.5。所以解决方案就是这个函数:

var parseIntRound = function(v)
{
    return parseInt(v + Math.sign(v)/2);
};
// or with modern syntactic sugar:
// const parseIntRound = v => parseInt(v + Math.sign(v)/2);

parseIntRound( 1.5) ===  2
parseIntRound( 0.5) ===  1
parseIntRound(-0.5) === -1
parseIntRound(-1.3) === -1
parseIntRound(-1.5) === -2
parseIntRound(-1.7) === -2

其中 Math.sign(v) returns 1 表示任何正数 (>0),-1 表示任何负数 (<0),0 表示正零(-0 表示负零) .

ES6 添加了一个名为 Math.trunc 的方法,使用它我们可以得到小数的整数部分

The Math.trunc() function returns the integer part of a number by removing any fractional digits.

Math.trunc(42.84) -> Returns 42
Math.trunc(5.3) -> Returns 5
Math.trunc(-4.3) -> Returns -4
Math.trunc(-3.123) -> Returns -3