Javascript |浮点数+区间循环

Javascript | Floating point numbers + interval loop

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

我怎样才能得到递减函数来在特定的时间内(例如1秒)从这个数字到0进行计算? 谢谢

预期值:

0.004178174922295
0.004178174922294
0.004178174922293
...
0

正如 raina77ow 和其他人在评论中指出的那样,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)

如果您可以将输入数字表示为 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);