web-dev-qa-db-ja.com

ループを使用してJavaScriptで0.01ずつ数値をインクリメントする方法は?

問題

1.20mから2.50mまでのメーターでコンソールの高さのリストを作成しようとしていました。

私はこのコードを使用しました:

_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
_

ご質問

  • どうしたの?
  • どうすれば修正できますか?

デモ

ここに a demo 面倒すぎてコンソールに入力できない場合:-)

25
hitautodestruct

あなたはこれをうまくやっています。問題は、浮動小数点数の不正確さにあります。

浮動小数点数がなぜ不正確なのですか?

この番号を表示したい場合は、次を使用します。

_heights[i].toFixed(2);
_

toFixed()は文字列を返すため、さらに数値演算を実行する場合は、float(parseFloat())に戻す必要があることに注意してください。

17
George Reith

これは、JavaScriptで数学がどのように機能するかという理由だけで、 this oneのように、それについて説明する多くの答えが見つかります。最も簡単な解決策は、すべてを100倍にして、配列に追加するときに除算することです。

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

toFixedを使用することもできますが、結果はStringになります。

8

これは、浮動小数点数が内部でどのように格納されるかによるもので、JavaScript固有ではありません。 .toFixed()を使用して、必要な精度で数値の文字列表現を保存できます。

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

文字列を保存してから実際の数値に変換し直したくない場合は、ステップを乗算して整数になるようにし、代わりに除算を保存できます。

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

あなたが現在数を持っているという事実以外の違いは、0.1の倍数が単一の精度で表されていることです。 2.4ではなく"2.40"

2
Ja͢ck

これは、マシンが基数2を使用しており、基数2では浮動小数点数で正確に表現できない基数10を使用しているためです。

このライブラリを使用してフォーマットできます: https://github.com/dtrebbien/BigDecimal.js

1
Red Alert

すでに述べたように、 toFixed()Stringを返し、 parseFloat()StringFloatに変換します。 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));
}
1
Vadym Tyemirov

メソッドtoFixed(float)を使用して、カンマの後の桁数を制限します

heights.Push(i.toFixed(2));
0
mcamier