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

问题描述

我正在 Javascript(或 JQuery)中寻找一个函数来从数字中删除表示无关精度的数字。我正在计算一个估计的概率,它可能是一个值范围 - 精确的小数不是很相关 - 只是左边的第一个非零小数。

  • 例如 0.0001,在这种情况下,这就是我想要显示内容
  • 但如果是 0.2453535 - 我只想显示 0.2。
  • 或者如果它是 0.015 - 我只想四舍五入以显示 0.02
  • 或者如果它是 0.00412 - 我只想四舍五入以显示 0.004

对实现这一目标的好方法有什么想法吗?

解决方法

使用 reg exp 是处理它的一种方式。它正在检查小于 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,{ 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,{ in: -0.010504,{ 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 = "" or lot "0" 后面跟着

([^0]) g3 = 一位数,但后面不是 0

([0-9]) g4 = 一位数后跟

\d* 任何未选择的数字结束数字

任何数字的完整解决方案:

function formatNumber(n) {
  v = n.toString().replace(/\.(0*)([^0])([0-9])\d*/,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.0025,0.00412,-0.0045,-2.01,-0.016,-0.012,-0.055,-0.15,-0.015,-4,102,0.0105,2.00015,-4.026];

resultwaiting=[0.0001,0.2,0.3,0.06,0.006,0.02,0.002,0.03,0.003,0.004,-0.005,-0.02,-0.01,-0.06,-0.2,0.01,2.0002,-4.03];

var i =0;
test.forEach(x => console.log(x,formatNumber(x),formatNumber(x) == resultwaiting[i++] ))

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...