hitautodestruct
hitautodestruct

Reputation: 20830

How to increment number by 0.01 in javascript using a loop?

Problem

I was trying to build out a list of heights in the console by meteres starting from 1.20m and ending up at 2.50m.

I used this code:

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

    heights.push(i);

}

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

If I console.log( heights ) I get:

1.2
1.21
1.22
1.23
...

But then at 1.37 I start getting:

1.37
1.3800000000000001
1.3900000000000001
1.4000000000000001
1.4100000000000001
1.4200000000000002
1.4300000000000002

Questions

Demo

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

    heights.push(i);

}

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

document.querySelector('#output').innerText = heights;
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>JS Bin</title>
</head>
<body>
  <div id="output"></div>
</body>
</html>

Upvotes: 34

Views: 27938

Answers (6)

Vadym Tyemirov
Vadym Tyemirov

Reputation: 8833

As it has been mentioned, toFixed() returns String, and parseFloat() converts String to Float. parseFloat() also removes trailing zeros, which makes sense, but was not working for my use case.

Here is an example of iteration using Float and retaining trailing zeroes.

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' ]

If trailing zeroes are not needed, the loop can be simplified as:

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

Upvotes: 1

mcamier
mcamier

Reputation: 426

Use the method toFixed(float), to limit the amount of digit after comma

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

Upvotes: 0

Ja͢ck
Ja͢ck

Reputation: 173612

This is due to how floating point numbers are stored internally, it's not JavaScript specific. You can use .toFixed() to store a string representation of the number with the desired accuracy, so:

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

If you want to avoid storing strings and then converting them back into an actual number, you can multiply the step so that it becomes a whole number and then store a division instead:

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

The difference besides the fact that you now have numbers is that multiple of 0.1 are represented in single accuracy, e.g. 2.4 instead of "2.40".

Upvotes: 2

Red Alert
Red Alert

Reputation: 3816

This is because machines use base 2, and you are using base 10 numbers that cannot be accurately represented in base 2 with a floating point number.

You can use this library to format it: https://github.com/dtrebbien/BigDecimal.js

Upvotes: 1

George Reith
George Reith

Reputation: 13476

You are doing this fine. The problem is with the inaccuracy of floating point numbers.

Why are floating point numbers so inaccurate?

If you wish to display this number then use:

heights[i].toFixed(2);

Note that toFixed() returns a string and you will have to convert back to a float (parseFloat()) if you want to perform more numerical operations.

Upvotes: 18

phenomnomnominal
phenomnomnominal

Reputation: 5515

This is just because of how math works in JavaScript, you can find lots of answers explaining about it - like this one. The easiest solution is to just do everything times 100, and then divide when adding to the array e.g.

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

You could use toFixed but that will give you a String as the result.

Upvotes: 9

Related Questions