0.02ずつ増加するbashループ

0.02ずつ増加するbashループ

試した増分として0.02を使用してbashでforループを作成したいと思います。

for ((i=4.00;i<5.42;i+=0.02))
do
commands
done

しかし、成功しませんでした。

答え1

シェルでループを避けてください。

算術を実行するには、awk次のようにしますbc

awk '
  BEGIN{
    for (i = 4.00; i < 5.42; i+ = 0.02)
      print i
  }'

または

bc << EOF
for (i = 4.00; i < 5.42; i += 0.02)  i
EOF

awk(とは対照的にbc)プロセッサに適用できる浮動小数点数値表現(doubleおそらくIEEE 754タイプ)。したがって、この数字は10進数の2進近似であるため、驚くことがあります。

$ gawk 'BEGIN{for (i=0; i<=0.3; i+=0.1) print i}'
0
0.1
0.2

1つを追加すると、OFMT="%.17g"欠落している理由を確認できます0.3

$ gawk 'BEGIN{OFMT="%.17g"; for (i=0; i<=0.5; i+=0.1) print i}'
0
0.10000000000000001
0.20000000000000001
0.30000000000000004
0.40000000000000002
0.5

bc任意の精度を持っているので、そのような問題はありません。

デフォルトでは、(出力形式を変更したり明示的な型指定をOFMT使用しない限り)浮動小数点数を表示するために、1,000,000以上の浮動小数点数は1e6以上に切り替わり、高い数字は小数部分(100000.02)が切り捨てられます。 100000と表示されます。)printfawk%.6g

たとえば、ループの各反復に対して特定のコマンドを実行するため、ループにシェルを使用する必要がある場合は、浮動小数点演算をサポートするシェルを使用するか、上記のいずれかのコマンドを使用zshして生成しますyashksh93値のリスト(またはseq利用可能な場合)と出力を繰り返します。

良い:

unset -v IFS # configure split+glob for default word splitting
for i in $(seq 4 0.02 5.42); do
  something with "$i"
done

または:

seq 4 0.02 5.42 | while IFS= read i; do
  something with "$i"
done

プロセッサの浮動小数点数の制限を超えない限り、浮動seq小数点近似によって発生したエラーは上記のバージョンよりもスムーズに処理されますawk

GNU コマンドがない場合は、seq次のように、より安定した機能を作成できます。

seq() { # args: first increment last
  bc << EOF
    for (i = $1; i <= $3; i += $2) i
EOF
}

この場合、これはより効率的ですseq 100000000001 0.000000001 100000000001.000000005。ただし、任意の高精度数値をサポートしていないコマンドに渡す場合は、あまり役に立ちません。

答え2

読書bash マニュアルページ次の情報を考慮すると:

for (( expr1 ; expr2 ; expr3 )) ; do list ; done

expr1まず、以下の算術評価で説明されている規則に従って算術式を評価します。 [...]

それから私達はこの部分を得ます。

算術評価

シェルは特定の状況で算術式の評価を可能にします(組み込みコマンドと算術拡張を参照)letdeclareオーバーフローを確認せずに固定幅整数で評価を行います。 [...]

forしたがって、整数以外の値を持つループは使用できないことが明らかです。

1つの解決策は、次のように、後で使用するためにすべてのループコンポーネントに100を掛けることです。

for ((k=400;k<542;k+=2))
do
    i=$(bc <<<"scale=2; $k / 100" )    # when k=402 you get i=4.02, etc.
    ...
done

開始値と終了値の有効桁数が同じ場合(この場合は3つ)、bcforループの各反復を呼び出さずに文字列処理を使用して10進値を生成できます。

    i="${k%??}.${k#?}"                 # POSIX; when k=402 you get i=4.02, etc.
    i="${k:0:1}.${k:1}"                # bash; when k=402 you get i=4.02, etc.

答え3

「seq」を使用 - 一連の数字を印刷します。

seq 最初の増分最後

for i in $(seq 4.00 0.02 5.42)
do 
  echo $i 
done

答え4

他の人が提案したように、bcを使用できます。

i="4.00"

while [[ "$(bc <<< "$i < 5.42")" == "1" ]]; do
    # do something with i
    i="$(bc <<< "$i + 0.02")"
done

関連情報