Как увеличить число на 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
Здесь демо, если вы слишком ленивы, чтобы ввести его в консоль: -)
Ответы
Ответ 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));
}