【问题标题】:Javascript | Floating point numbers + interval loopJavascript |浮点数 + 区间循环
【发布时间】:2020-10-14 22:23:32
【问题描述】:

我有一个浮点数(例如):0.004178174922295

如何让递减函数在特定时间(例如 1 秒)内将此数字计算为 0? 谢谢。

预期值:

0.004178174922295
0.004178174922294
0.004178174922293
...
0

【问题讨论】:

  • 另外,这个数字的来源是什么?用户输入、服务器端数据、一些计算结果?我在问,因为根据这一点,使用整数可能会更好,使用所有这些 0.000... 只是为了显示该数字。
  • 只是一个数字(常数)。
  • 0.004178174922294 - 0.000000000000001 !== 0.004178174922293
  • @XTRUST.ORG 有什么要求?使用字符串好吗?

标签: javascript loops numbers settimeout floating


【解决方案1】:

正如 raina77ow 和其他人在 cmets 中指出的那样,operations with decimal numbers are problematic in JS, approximations are made and the results may be inexact

一种解决方法是将无穷小数转换为大整数,使用它们并在最后将它们转换回来。

这就是你要找的吗?请告诉我。

编辑 您可以要求在一定时间内完成倒计时,它确实适用于合理的数字,但在 Javascript the minimum interval is of 10 milliseconds 中,您不能调用比这更短的时间间隔。使用您提供的示例编号0.004178174922295,这就像从4178174922295 倒数到零。这需要每 10 毫秒间隔近 1325 年(如果我的数学是正确的,无论哪种方式,我都希望你会通过更短的时间间隔)。

function infinitesimalCountDown(num, seconds) {
  // I create a coeficient to convert the decimal to an int
  // Will be a big number starting with "1" and followed by a bunch of zeroes
  let coefString = '1';
  for(let i=0; i<num.toString().length-2; i++) {
    coefString += '0';
  }

  const coef = Number(coefString);

  // This has the digits from the original original but it's an int
  let counter = Math.round(num*coef);

  // Now I can just treat it as an int and convert it back for the output
  const icdInterval = setInterval(() => {
    counter--;
    console.log(counter/coef);
    if(counter <= 0) clearInterval(icdInterval);
  }, Math.round(seconds*1000/counter));
}

console.log("It works with a short number");

infinitesimalCountDown(0.0041, 10);

setTimeout(() => {
  console.log("It doesn't work with a long number");
  infinitesimalCountDown(0.004178174922295, 3000);
}, 12 * 1000);

如果您对 Javascript 能够处理它所必需的步骤感到满意,您可以执行以下操作:

function infinitesimalCountDown(num, seconds) {
  let coefString = '1'
  
  for(let i=0; i<num.toString().length-2; i++) {
    coefString += '0'
  }

  const coef = Number(coefString)
  
  let counter = Math.round(num*coef)
  
  let steps = seconds * 1000 / counter
  
  steps = steps < 100 ? 100 : steps
  
  let step = 1
  
  if(steps == 100) {
    step = counter / ((seconds * 1000) / steps)
  }
  
  console.log(step)
  
  const icdInterval = setInterval(() => {
    counter -= step;
    if(counter <= 0) {
      counter = 0
      clearInterval(icdInterval)
    }
    console.log(counter/coef)
  }, steps)
}

infinitesimalCountDown(0.004178174922295, 5)

【讨论】:

    【解决方案2】:

    如果您可以将输入数字表示为number 类型(因此没有很多小数),您可以使用普通数字减法来做到这一点。

    在这里,重要的是要减去要减去的单位。您可以使用Math.pow 获取该单元。

    从这个floating point guide开始,需要对计数进行四舍五入,这可以使用toFixed函数来完成。

    let input = 0.004178174922295;
    const decimalCount = input.toString().length - 2;
    const unit = Math.pow(10, -1 * decimalCount);
    
    console.log(input);
    const loopInterval = setInterval(() => {
      input = Number((input - unit).toFixed(decimalCount));
      console.log(input);
      if (input == 0) {
        clearInterval(loopInterval);
      }
    }, 1000);

    如果输入的数字有很多小数,所以接收为string类型(使用number类型无法呈现),则需要使用字符串进行减法,如下所示。

    const input = '0.0041781749222934534534534535';
    const inputArr = input.split('.');
    
    const intNum = inputArr[0]; // Present integer
    let decimals = inputArr[1]; // Present decimals after '.'
    const unit = 1;
    
    function replaceAt(str, index, replace) {
      return str.substring(0, index) + replace + str.substring(index + 1);
    }
    
    console.log(input);
    const loopInterval = setInterval(() => {
      let index = decimals.length - 1;
      while (parseInt(decimals[index]) < unit) {
        decimals = replaceAt(decimals, index --, '9');
      }
      decimals = replaceAt(decimals, index, `${parseInt(decimals[index]) - unit}`);
      
      console.log(`${intNum}.${decimals}`);
    }, 1000);

    【讨论】:

    • 谢谢!是否可以在特定时间内完成所有计算?例如,我想在特定的时间内从最大值迭代到零。目前它每 1 秒减去 1 个值。
    • 由此(webplatform.github.io/docs/dom/Window/setTimeout/…),您可以设置的最小毫秒为 4ms。所以它不适用于只能描述字符串的长数字。
    猜你喜欢
    • 2016-07-26
    • 1970-01-01
    • 1970-01-01
    • 2013-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-05
    相关资源
    最近更新 更多