Meh*_*had 12 bash for floating-point
我想在 bash 中使用 0.02 作为我尝试的增量进行 for 循环
for ((i=4.00;i<5.42;i+=0.02))
do
commands
done
Run Code Online (Sandbox Code Playgroud)
但它没有用。
Sté*_*las 20
避免外壳中的循环。
如果要进行算术运算,请使用awk或bc:
awk '
BEGIN{
for (i = 4.00; i < 5.42; i+ = 0.02)
print i
}'
Run Code Online (Sandbox Code Playgroud)
或者
bc << EOF
for (i = 4.00; i < 5.42; i += 0.02) i
EOF
Run Code Online (Sandbox Code Playgroud)
请注意awk(与 相反bc)适用于您的处理器double浮点数表示(可能是IEEE 754类型)。因此,由于这些数字是这些十进制数字的二进制近似值,您可能会有一些惊喜:
$ gawk 'BEGIN{for (i=0; i<=0.3; i+=0.1) print i}'
0
0.1
0.2
Run Code Online (Sandbox Code Playgroud)
如果添加一个,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
Run Code Online (Sandbox Code Playgroud)
bc 做任意精度所以没有这种问题。
请注意,在默认情况下(除非你修改与输出格式OFMT或使用printf有明确的格式规范),awk用途%.6g,用于显示浮点数,因此会切换到1E6及以上浮点数上述1,000,000,截断高数的小数部分(100000.02将显示为 100000)。
如果您确实需要使用 shell 循环,因为例如您想为该循环的每次迭代运行特定命令,请使用具有浮点算术支持的 shell,例如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
Run Code Online (Sandbox Code Playgroud)
或者:
seq 4 0.02 5.42 | while IFS= read i; do
something with "$i"
done
Run Code Online (Sandbox Code Playgroud)
除非您突破处理器浮点数的限制,否则会seq比上述awk版本更优雅地处理由浮点近似引起的错误。
如果你没有seq(一个 GNU 命令),你可以制作一个更可靠的函数,如:
seq() { # args: first increment last
bc << EOF
for (i = $1; i <= $3; i += $2) i
EOF
}
Run Code Online (Sandbox Code Playgroud)
这对于像seq 100000000001 0.000000001 100000000001.000000005. 但是请注意,如果我们要将它们传递给不支持它们的命令,那么拥有任意高精度的数字将无济于事。
roa*_*ima 19
阅读bash 手册页可提供以下信息:
for (( expr1 ; expr2 ; expr3 )) ; do list ; done首先,
expr1根据以下“算术评估”中描述的规则对算术表达式进行评估。[...]
然后我们得到这个部分
算术评估
在某些情况下,shell 允许对算术表达式进行求值(请参阅
let和declare内置命令和算术扩展)。评估以固定宽度的整数进行,不检查溢出 [...]
因此可以清楚地看到,您不能使用for具有非整数值的循环。
一种解决方案可能是简单地将所有循环组件乘以 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
Run Code Online (Sandbox Code Playgroud)
如果起始值和结束值的有效数字数相同(在此示例中为三个),则可以避免bc循环每次迭代的调用,而是使用字符串处理来生成十进制值,
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.
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
13544 次 |
| 最近记录: |