javascript - 自定义四舍五入到最接近的 0.05

标签 javascript

我想根据以下条件将自定义舍入到接近 0.05。这很难解释,但下面的例子很容易理解。

12.910 - 12.90
12.920 - 12.90
12.930 - 12.90
12.940 - 12.90
12.941 - 12.95
12.950 - 12.95

12.960 - 12.95
12.970 - 12.95
12.980 - 12.95
12.990 - 12.95
12.991 - 13.00 
13.000 - 13.00 

我尝试了几个函数,但它正在将 12.98 向上舍入到 13.00。

function   customRound( num) {
    return Math.round(num * 20) / 20;
}

最佳答案

从视觉上看,您的舍入算法看起来像这样:
A number line, extending from 12.94 to 13.04, with the interval (12.94, 12.99] marked in red and the interval (12.99, 13.04] marked in blue. A red dot is at 12.95, and a blue dot is at 13.00.
点是您要在该间隔内舍入到的位置。 ( 表示区间的开放端,] 表示区间的封闭端。(12.99 属于红色区间。)我们将通过操纵线来实现此算法以匹配 Math.floor 的。

首先,我们来处理整数。

num * 100

The same number line, but the scale has changed. Line: [1294, 1304], red: (1294, 1299] with dot at 1295, blue: (1299, 1304] with dot at 1300.

您的舍入区间是左开右闭,但 Math.floor 是左闭右开。我们可以通过乘以 −1 来翻转直线以匹配:

  num *  100 * -1
⇒ num * -100

The number line has been flipped. Line: [-1304, -1294], blue: [-1304, -1299) with dot at -1300, red: [-1299, -1294) with dot at -1295.

舍入区间的长度是 5,所以我们需要将区间的末端放在 5 的倍数上...

num * -100 - 1

The intervals have shifted 1 towards negative infinity. Line: [-1305, -1295], blue: [-1305, -1300) with dot at -1301, red: [-1299, -1294) with dot at -1296.

...在除以 5 以匹配 Math.floor 之前。

 (num * -100 - 1  ) / 5
⇒ num *  -20 - 0.2

The scale has changed again. Line: [-261, -259], blue: [-261, -260) with dot at -260.2, red: [-260, -259) with dot at -259.2.

现在我们可以发言了。

return Math.floor(num * -20 - 0.2);

The same number line, now with Math.floor arrows! Blue arrow pointing to -261, red arrow pointing to -260.

通过乘以 5 返回到原来的比例:

return Math.floor(num * -20 - 0.2) * 5;

Another scale change. Line: [-1305, -1295], blue: [-1305, -1300) with dot at -1301 and arrow at -1305, red: [-1299, -1294) with dot at -1296 and arrow at -1300.

通过添加 4 将返回值移到点:

return Math.floor(num * -20 - 0.2) * 5 + 4;

The arrows have moved. Blue arrow pointing to -1301, red arrow pointing to -1296.

取消我们之前做的对齐:

  return Math.floor(num * -20 - 0.2) * 5 + 4 + 1;
⇒ return Math.floor(num * -20 - 0.2) * 5 + 5;

The intervals have shifted 1 towards positive infinity. Line: [-1304, -1294], blue: [-1304, -1299) with dot and arrow at -1300, red: [-1299, -1294) with dot and arrow at -1295.

撤消翻转:

  return (Math.floor(num * -20 - 0.2) *  5 + 5) * -1;
⇒ return  Math.floor(num * -20 - 0.2) * -5 - 5;

The number line has been flipped again. Line: [1294, 1304], red: (1294, 1299] with dot and arrow at 1295, blue: (1299, 1304] with dot and arrow at 1300.

然后将整个值除以 100 得到原来的比例:

  return (Math.floor(num * -20 - 0.2) * -5    - 5) / 100;
⇒ return  Math.floor(num * -20 - 0.2) * -0.05 - 0.05;

The original number line is back, now with arrows pointing at the dots. Line: [12.94, 13.04], red: (12.94, 12.99] with arrow and dot at 12.95, blue: (12.99, 13.04] with arrow and dot at 13.00.

使用 Robin Zigmond 的测试框架,

function customRound(num) {
    return Math.floor(num * -20 - 0.2) * -0.05 - 0.05;
}

// test desired results
var tests = [12.91, 12.92, 12.93, 12.94, 12.941, 12.95, 12.96, 12.97, 12.98, 12.99, 12.991, 13];

for (var i=0; i<tests.length; i++) {
  console.log(`${tests[i].toFixed(3)} - ${customRound(tests[i]).toFixed(2)}`);
}

关于javascript - 自定义四舍五入到最接近的 0.05,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53198773/

相关文章:

javascript - 使用 Greasemonkey/Tampermonkey 保存数据供以后检索

javascript - 主干数据类型 - 类型转换?

php - 从 php 代码创建一个 cytoscape 树

javascript - 是否可以将生成器中的项目异步收集到数组中?

javascript - 单个 HTML 表单中的多个提交按钮

Javascript 验证 w3c

javascript - 使用谷歌工作表脚本移动过滤值(复制和粘贴值),同时忽略列标题/标题

javascript - Lodash 嵌套循环搜索

javascript - lambda javascript 的正确语法

javascript - 是什么导致我的 chrome 扩展程序的 background.js 卡住并且不响应消息