Избегайте петель в ракушках.
Если вы хотите сделать арифметику, используйте 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 ). В результате, поскольку эти числа являются двоичными приближениями этих десятичных чисел, у вас могут быть некоторые сюрпризы:
$ gawk 'BEGIN{for (i=0; i<=0.3; i+=0.1) print i}'
0
0.1
0.2
Если вы добавите, 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
или не используете printf
явные спецификации формата), awk
используется %.6g
для отображения чисел с плавающей запятой, поэтому переключился бы на 1e6 и выше для чисел с плавающей запятой свыше 1 000 000 и урезал дробную часть для больших чисел (100000.02 будет отображаться как 100000).
Если вам действительно нужно использовать цикл оболочки, так как , например , вы хотите запустить определенные команды для каждой итерации этого цикла, либо использовать оболочку с плавающей запятой арифметической поддержки , как zsh
, yash
или ksh93
или создать список значений с помощью одной команды , как указаны выше (или, 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
вышеприведенная версия.
Если у вас нет seq
(команда GNU), вы можете сделать более надежную функцию как:
seq() { # args: first increment last
bc << EOF
for (i = $1; i <= $3; i += $2) i
EOF
}
Это будет работать лучше для таких вещей, как seq 100000000001 0.000000001 100000000001.000000005
. Однако обратите внимание, что наличие чисел с произвольно высокой точностью мало поможет, если мы собираемся передать их командам, которые их не поддерживают.