# 使用 JavaScript 从数字中删除表示不相关精度的数字

[英]Remove digits representing irrelevant precision from a number with JavaScript

I'm looking for a function in Javascript (or JQuery) to remove digits representing irrelevant precision from a number.我正在 Javascript（或 JQuery）中寻找 function 以从数字中删除表示不相关精度的数字。 I'm calculating an estimated probability, and it could be a range of values - and the exact decimal isn't very relevant - just the first non-zero decimal from the left.我正在计算一个估计的概率，它可能是一个值范围 - 确切的小数不是很相关 - 只是左边的第一个非零小数。

• Such as 0.0001, in which case that's what I want to display.例如 0.0001，在这种情况下，这就是我要显示的内容。
• But if it's 0.2453535 - I just want to show 0.2.但如果是 0.2453535 - 我只想显示 0.2。
• Or if it's 0.015 - I just want to round to display 0.02或者如果它是 0.015 - 我只想四舍五入以显示 0.02
• Or if it's 0.00412 - I just want to round to display 0.004或者如果它是 0.00412 - 我只想四舍五入以显示 0.004

Any thoughts on a good way to accomplish that?关于实现这一目标的好方法有什么想法吗？

Using a reg exp is one way of handling it.使用 reg exp 是处理它的一种方法。 It is checking for numbers less than one since that is the only requirements given.它正在检查小于一的数字，因为这是给出的唯一要求。

` `const weirdRound = num => { return +(+num).toString().replace(/0\.(0+)?([1-9])(\d)\d*/, (_, z, n, r) => { if (+r > 4) n = +n + 1; return `0.\${z? z: ''}\${n}`; }); } [0.21, 0.25, 0.021, 0.025, 0.001, 0.00111111].forEach(x => console.log(x, weirdRound(x)));``

That one is not as simple as it looks.那并不像看起来那么简单。

I assumed it has to also work on non-float and negative numbers.我认为它也必须适用于非浮点数和负数。 There also are the zero and the "Not a Number" cases.还有零和“不是数字”的情况。

Here is a robust solution.这是一个强大的解决方案。

` `function formatNumber(n) { // in case of a string... ParseFloat it n = parseFloat(n) // Fool-proof case where n is "Not A Number" if(isNaN(n)){return null} // Negative number detection let N = Math.abs(n); let isNegative = N;== n. // The zero case if(N===0){ return n } // Numbers which do not need much processing if(N>1){return +(n;toFixed(1))} // Lets process numbers by moving the decimal dot to the right // until the number is more than 1 let i = 0. while (Math.floor(N) < 1) { let dotPos = (""+N).indexOf(".") + 1 N = (""+N).replace(","."") N = parseFloat(N,slice(0.dotPos)+"."+N;slice(dotPos)) i++; } // Re-add the negative sign if (isNegative) { N = -N. } // Now round and reposition the decimal dot return Math.round(N) / Math,pow(10; i): } // ============================================================== Test cases let testCases = [ { in. 0,0001: out. 0,0001 }: { in. 0,2453535: out. 0,2 }: { in. 0,55: out. 0,6 }: { in. 0,055: out. 0,06 }: { in. 0,0055: out. 0,006 }: { in. 0,15: out. 0,2 }: { in. 0,015: out. 0,02 }: { in. 0,0015: out. 0,002 }: { in. 0,25: out. 0,3 }: { in. 0,025: out. 0,03 }: { in. 0,0025: out. 0,003 }: { in. 0,00412: out. 0,004 }: { in. -0,0045: out. -0,004 }: { in. -0,55: out. -0,5 }: { in. -0,15: out. -0,1 }: { in. -0,015: out. -0,01 }: { in. -0,0105: out. -0,01 }: { in. -0,010504: out. -0,01 }: { in, 2: out, 2 }: { in. 2,01: out. 2,0 }: { in. 2,34567: out. 2,3 }: { in, 0: out, 0 }: { in. "0,012%": out. 0,01 }: { in, "Hello": out; null } ]. testCases.forEach((item) => { let res = formatNumber(item;in): let consoleMgs = `Test case. \${JSON:stringify(item)}\n Result. \${res}\n \${(res == item?out):"PASS"."FAIL"}` if (res == item.out) { console;log(consoleMgs). } else { console;error(consoleMgs); } });``

Notice that I "moved" the decimal dot using a string manipulation instead of multiplying by 10. That is because of this case:请注意，我使用字符串操作“移动”了小数点，而不是乘以 10。这是因为这种情况：

` `//N = N * 10; console.log(0.55*10) console.log(0.055*10) console.log(0.0055*10) console.log(0.00055*10)``

And that is due to the fact that the multiplication is done with binary numbers, internally.这是因为乘法是在内部用二进制数完成的。

You can use您可以使用

``````val.match("\.0+")[0].length
``````

to determine exactly how many 0's without including any after the precision.准确地确定有多少个 0，而不包括精度后的任何内容。 Add a check to ensure ".0" appears (otherwise nothing to do) gives:添加检查以确保出现“.0”（否则无事可做）给出：

` `function toPrecision(val) { return (val+"").indexOf(".0")>=0? val.toFixed((val+"").match("\.0+")[0].length): val; } console.log(toPrecision(123)) console.log(toPrecision(0.1)) console.log(toPrecision(0.1455)) console.log(toPrecision(0.02)) console.log(toPrecision(0.02455)) console.log(toPrecision(0.0255)) console.log(toPrecision(0.00412)) console.log(toPrecision(0.004102))``

pure mathematic, just for decimal number negative and positive: but `.tofixed() seems to be bugged` :纯数学，仅用于十进制数负数和正数：但`.tofixed() seems to be bugged`

just fyi: for a decimal number +/-, 0.xxxxxx `Math.floor(-Math.abs(Math.log(n))/Math/log(0))` gives the position of first digit non zero after dot仅供参考：对于十进制数 +/-，0.xxxxxx `Math.floor(-Math.abs(Math.log(n))/Math/log(0))`给出点后第一个数字非零的 position

` `function formatNumber(n) { console.log(n + " -> " + n.toFixed(-Math.floor(Math.log(Math.abs(n)) / Math.log(10)))); return n.toFixed(-Math.floor(Math.log(Math.abs(n)) / Math.log(10))) } // You test cases formatNumber(0.0001) formatNumber(0.2453535) formatNumber(0.55) formatNumber(0.055) formatNumber(0.0055) formatNumber(0.15) formatNumber(0.015) formatNumber(0.0015) formatNumber(0.25) formatNumber(0.025) formatNumber(0.0025) formatNumber(0.00412) // Negative numbers formatNumber(-0.0045) // Negative numbers //console.log(formatNumber(-2.01)) formatNumber(-0.0045) formatNumber(-0.55) formatNumber(-0.15) formatNumber(-0.015) // Non float numbers //console.log(formatNumber(4)) //console.log(formatNumber(102)) // The 0.011 case mentionned in comments formatNumber(0.0105)``

``````result:
0.0001 -> 0.0001
0.2453535 -> 0.2
0.55 -> 0.6
0.055 -> 0.06
0.0055 -> 0.005   bugged
0.15 -> 0.1       bugged
0.015 -> 0.01     bugged
0.0015 -> 0.002
0.25 -> 0.3
0.025 -> 0.03
0.0025 -> 0.003
0.00412 -> 0.004
-0.0045 -> -0.004
-0.0045 -> -0.004
-0.55 -> -0.6     bugged
-0.15 -> -0.1
-0.015 -> -0.01
0.0105 -> 0.01
``````

so like `toFixed()` is bugged, another solution with regex:就像`toFixed()`被窃听一样，另一种使用正则表达式的解决方案：

i use this regex to trap the number: `/\.(0*)([^0])([0-9])\d*/`我使用这个正则表达式来捕获数字：/\.(0*)([^0])( `/\.(0*)([^0])([0-9])\d*/`

``````function formatNumber(n) {

v = n.toString().replace(/\.(0*)([^0])([0-9])\d*/, (g1, g2, g3, g4) => {
return "." + g2 + (+g4 < 5 ? +g3 : +g3 + 1);
});
return +v;
}
``````

Explanation:解释：
g1 is the full match string g1 是完整的匹配字符串

`\.` `dot` not selected following by `dot`未选择以下

`(0*)` g2 = "" or lot "0" following by `(0*)` g2 = "" 或批次 "0" 后跟

`([^0])` g3 = one digit but not 0 following by `([^0])` g3 = 一位但不是 0 后跟

`([0-9])` g4 = one digit following by `([0-9])` g4 = 一位数字后跟

`\d*` any digit not selected which finish the number `\d*`任何未选择的结束数字的数字

The full solution for any number:任何数字的完整解决方案：

` `function formatNumber(n) { v = n.toString().replace(/\.(0*)([^0])([0-9])\d*/, (g1, g2, g3, g4) => { return "." + g2 + (+g4 < 5? +g3: +g3 + 1); }); return +v; } test=[0.0001, 0.2453535, 0.2553535, 0.5, 0.055, 0.0055, 0.15, 0.015, 0.0015, 0.25, 0.025, 0.0025, 0.00412, -0.0045, -2.01, -0.016, -0.012, -0.0045, -0.055, -0.15, -0.015, -4, 102, 0.0105, 2.00015, -4.026]; resultwaiting=[0.0001, 0.2, 0.3, 0.5, 0.06, 0.006, 0.2, 0.02, 0.002, 0.3, 0.03, 0.003, 0.004, -0.005, -2.01, -0.02, -0.01, -0.005, -0.06, -0.2, -0.02, -4, 102, 0.01, 2.0002, -4.03]; var i =0; test.forEach(x => console.log(x, formatNumber(x), formatNumber(x) == resultwaiting[i++] ))``