从具有 JavaScript 的数字中删除代表不相关精度的数字
Remove digits representing irrelevant precision from a number with JavaScript
我正在 Javascript(或 JQuery)中寻找一个函数,用于从数字中删除表示不相关精度的数字。我正在计算一个估计的概率,它可能是一个值范围 - 确切的小数不是很相关 - 只是从左边开始的第一个非零小数。
- 比如0.0001,这样就是我要显示的。
- 但如果它是 0.2453535 - 我只想显示 0.2。
- 或者如果它是 0.015 - 我只想四舍五入以显示 0.02
- 或者如果它是 0.00412 - 我只想四舍五入以显示 0.004
有什么好的方法可以实现吗?
使用正则表达式是处理它的一种方法。它正在检查小于 1 的数字,因为这是唯一给出的要求。
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)));
那个并不像看起来那么简单
我假设它也必须适用于非浮点数和负数。还有零和“不是数字”的情况。
这是一个可靠的解决方案。
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);
}
});
请注意,我使用字符串操作“移动”了小数点,而不是乘以 10。这是因为这种情况:
//N = N * 10;
console.log(0.55*10)
console.log(0.055*10)
console.log(0.0055*10)
console.log(0.00055*10)
这是因为乘法是在内部用二进制数完成的。
More details here.
您可以使用
val.match("\.0+")[0].length
确定精确度后不包含任何 0 的确切数量。添加检查以确保出现“.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))
纯数学,只求十进制数的负数和正数:
但是 .tofixed() seems to be bugged
:
仅供参考:对于十进制数+/-,0.xxxxxx Math.floor(-Math.abs(Math.log(n))/Math/log(0))
给出点
后第一个非零数字的位置
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
所以像 toFixed()
被窃听了,另一个使用正则表达式的解决方案:
我使用这个正则表达式来捕获数字:/\.(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;
}
解释:
g1 是完整匹配字符串
\.
dot
未选择跟随
(0*)
g2 = "" 或手数 "0" 后跟
([^0])
g3 = 一位数字但不为 0 后跟
([0-9])
g4 =
后面的一位数
\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;
}
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++] ))
我正在 Javascript(或 JQuery)中寻找一个函数,用于从数字中删除表示不相关精度的数字。我正在计算一个估计的概率,它可能是一个值范围 - 确切的小数不是很相关 - 只是从左边开始的第一个非零小数。
- 比如0.0001,这样就是我要显示的。
- 但如果它是 0.2453535 - 我只想显示 0.2。
- 或者如果它是 0.015 - 我只想四舍五入以显示 0.02
- 或者如果它是 0.00412 - 我只想四舍五入以显示 0.004
有什么好的方法可以实现吗?
使用正则表达式是处理它的一种方法。它正在检查小于 1 的数字,因为这是唯一给出的要求。
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)));
那个并不像看起来那么简单
我假设它也必须适用于非浮点数和负数。还有零和“不是数字”的情况。
这是一个可靠的解决方案。
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);
}
});
请注意,我使用字符串操作“移动”了小数点,而不是乘以 10。这是因为这种情况:
//N = N * 10;
console.log(0.55*10)
console.log(0.055*10)
console.log(0.0055*10)
console.log(0.00055*10)
这是因为乘法是在内部用二进制数完成的。
More details here.
您可以使用
val.match("\.0+")[0].length
确定精确度后不包含任何 0 的确切数量。添加检查以确保出现“.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))
纯数学,只求十进制数的负数和正数:
但是 .tofixed() seems to be bugged
:
仅供参考:对于十进制数+/-,0.xxxxxx Math.floor(-Math.abs(Math.log(n))/Math/log(0))
给出点
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
所以像 toFixed()
被窃听了,另一个使用正则表达式的解决方案:
我使用这个正则表达式来捕获数字:/\.(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;
}
解释:
g1 是完整匹配字符串
\.
dot
未选择跟随
(0*)
g2 = "" 或手数 "0" 后跟
([^0])
g3 = 一位数字但不为 0 后跟
([0-9])
g4 =
\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;
}
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++] ))