简体   繁体   中英

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

  • What's going on?
  • How do I fix it?

Demo

Here's a demo if you're too lazy to type it in your console :-)

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.

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 eg

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.

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, eg 2.4 instead of "2.40" .

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

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));
}

使用方法toFixed(float)来限制逗号后的数字量

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM