Подтвердить что ты не робот

Как увеличить число на 0,01 в javascript, используя цикл?

Проблема

Я пытался создать список высот в консоли с метрами начиная с 1.20 м и заканчивая на 2.50 м.

Я использовал этот код:

var heights = [];
for ( var i=1.20, l=2.5; i<l; i+=0.01 ){

    heights.push(i);

}

heights = heights.join('\n');

Если я console.log( heights ), я получаю:

1.2
1.21
1.22
1.23
...

Но затем в 1.37 я начинаю получать:

1.37
1.3800000000000001
1.3900000000000001
1.4000000000000001
1.4100000000000001
1.4200000000000002
1.4300000000000002

Вопросы

  • Что происходит?
  • Как это исправить?

Demo

Здесь демо, если вы слишком ленивы, чтобы ввести его в консоль: -)

4b9b3361

Ответ 1

Вы делаете это хорошо. Проблема заключается в неточности чисел с плавающей запятой.

Почему числа с плавающей запятой настолько неточны?

Если вы хотите отобразить этот номер, используйте:

heights[i].toFixed(2);

Обратите внимание, что toFixed() возвращает строку, и вам нужно будет преобразовать обратно в float (parseFloat()), если вы хотите выполнять более числовые операции.

Ответ 2

Это просто из-за того, как математика работает в JavaScript, вы можете найти множество ответов, объясняющих об этом - например this. Самое простое решение - просто делать все 100 раз, а затем делиться при добавлении в массив, например.

var heights = [], i, l;
for (i = 120; i < 250; i += 1){    
    heights.push(i / 100);    
}

Вы можете использовать toFixed, но в результате вы получите String.

Ответ 3

Это связано с тем, что числа с плавающей запятой сохраняются внутри, а не для JavaScript. Вы можете использовать .toFixed() для хранения строкового представления числа с требуемой точностью, поэтому:

heights.push(i.toFixed(2));

Если вы хотите избежать хранения строк и затем преобразовать их обратно в фактическое число, вы можете умножить шаг так, чтобы он стал целым числом, а затем сохранил деление:

for (var i = 120; i <= 250; ++i) {
    heights.push(i / 100);
}

Различие, кроме того факта, что у вас теперь есть числа, состоит в том, что несколько из 0.1 представлены с единственной точностью, например. 2.4 вместо "2.40".

Ответ 4

Это связано с тем, что машины используют базу 2, и вы используете базовые 10 чисел, которые не могут быть точно представлены в базе 2 с числом с плавающей запятой.

Вы можете использовать эту библиотеку для ее форматирования: https://github.com/dtrebbien/BigDecimal.js

Ответ 5

Используйте метод toFixed (float), чтобы ограничить количество цифр после запятой

heights.push(i.toFixed(2));

Ответ 6

Как уже упоминалось, toFixed() возвращает String и parseFloat() преобразует String в Float. parseFloat() также удаляет конечные нули, что имеет смысл, но не работает для моего использования.

Вот пример итерации с использованием Float и сохранения конечных нулей.

var i = 0.9,
  floats = [];

while (i < 2) {
  i = (i + 0.1).toFixed(1);
  floats.push(i);
  i = parseFloat(i);
}
console.log(floats);


[ '1.0',
  '1.1',
  '1.2',
  '1.3',
  '1.4',
  '1.5',
  '1.6',
  '1.7',
  '1.8',
  '1.9',
  '2.0' ]

Если конечные нули не нужны, цикл можно упростить как:

while (i < 2) {
  floats.push(i);
  i = parseFloat((i + 0.1).toFixed(1));
}