在bash中更简单的数学帮助!

时间:2009-12-08 08:33:35

标签: bash syntax math

在与this question相同的帖子中,我正在给出另一个镜头并请求SO帮助解决我应该如何解决这个问题。我正在编写一个bash脚本,需要执行以下操作:

  1. 我在xy中有一个半径为r的圈子。
  2. 我指定resolution,这是我正在检查的点之间的距离。
  3. 我需要循环遍历x和y(从-r到r)并检查当前(x,y)是否在圆圈中,但是我将循环遍及离散的ij
  4. 然后ij需要从-r/resolution转到+r/resolution
  5. 在循环中,需要发生的是echo "some_text i*resolution j*resolution 15.95 cm"(注意缺少$因为我无能为力)。这个输出就是我真正想要的。
  6. 到目前为止我最好的拍摄:

    r=40.5
    resolution=2.5
    end=$(echo "scale=0;$r/$resolution") | bc
    
    for (( i=-end; i<=end; i++ ));do
        for (( j=-end; j<=end; j++ ));do
            x=$(echo "scale=5;$i*$resolution") | bc
            y=$(echo "scale=5;$j*$resolution") | bc
            if (( x*x + y*y <= r*r ));then      <-- No, r*r will not work
                echo "some_text i*resolution j*resolution 15.95 cm"
            fi
        done
    done 
    

    我对bash已经足够了,可能会像我上一个问题中某人所建议的那样查看ksh,但是如果有人知道执行此操作的正确方法,请告诉我!无论如何解决这个问题,它都将确定我未来的气质,以确保打击bash脚本。

4 个答案:

答案 0 :(得分:1)

您可能希望将管道包含在$()中的bc中。而不是。

end=$(echo "scale=0;$r/$resolution") | bc

使用

end=$(echo "scale=0;$r/$resolution" | bc)

应该有所帮助。

编辑这是一个解决方案。

r=40.5
resolution=2.5
end=$(echo "scale=0;$r/$resolution" | bc)

for i in $(seq -${end} ${end}); do
    for j in $(seq -${end} ${end}); do
        x=$(echo "scale=5;$i*$resolution" | bc)
        y=$(echo "scale=5;$j*$resolution" | bc)

        check=$(echo "($x^2+$y^2)<=$r^2" | bc)    
        if [ ${check} -eq '1' ]; then
            iRes=$(echo "$i*$resolution" | bc)
            jRes=$(echo "$j*$resolution" | bc)      
            echo "some_text $iRes $jRes 15.95 cm"
        fi
    done
done

答案 1 :(得分:1)

如前所述,使用bc,awk,ksh或其他脚本语言可能最好解决这个问题。

Pure Bash。实际上需要浮点运算的简单问题有时可以仅使用整数转换为某种定点运算。以下解决方案模拟小数点后的2位小数。 如果这个精度足够的话,循环内部就不需要管道和外部过程。

factor=100                                      # 2 digits after the decimal point
r=4050                                          # the representation of 40.50
resolution=250                                  # the representation of  2.50
end=$(( (r/resolution)*factor ))                # correct the result of the division

for (( i=-end; i<=end; i+=factor )); do
    for (( j=-end; j<=end; j+=factor )); do
        x=$(( (i*resolution)/factor ))          # correct the result of the division
        y=$(( (j*resolution)/factor ))          # correct the result of the division 
        if [ $(( x*x + y*y )) -le $(( r*r )) ] ;then     # no correction needed
                        echo "$x $y ... "
        fi
    done
done

echo -e "resolution = $((resolution/factor)).$((resolution%factor))"
echo -e "r          = $((r/factor)).$((r%factor))"

答案 2 :(得分:0)

你还没有听说过(g)awk ??那你应该去了解它。从长远来看,它将使您受益。将您的bash脚本翻译为awk。

awk 'BEGIN{
    r=40.5
    resol=2.5
    end = r/resol
    print end
    for (i=-end;i<=end;i++) {
        for( j=-end;j<=end;j++ ){
            x=sprintf("%.5d",i*resol)
            y=sprintf("%.5d",j*resol)
            if ( x*x + y*y <= r*r  ){
                print ".......blah blah ......"
            }
        }    
    }
}'

答案 3 :(得分:0)

它看起来更像是一个bc脚本,而不是一个Bash,所以这里有:

#!/usr/bin/bc -q
/* -q suppresses a welcome banner - GNU extension? */ 
r = 40.5
resolution = 2.5

scale = 0
end = r / resolution

scale = 5

for ( i = -end; i <= end; i++ ) {
    /* moved x outside the j loop since it only changes with i */
    x = i * resolution
    for ( j = -end; j <= end; j++ ) {
        y = j * resolution
        if ( x^2 * y^2 <= r^2 ) {
            /*
               the next few lines output on separate lines, the quote on 
               a line by itself causes a newline to be created in the output
               numeric output includes newlines automatically
               you can comment this out and uncomment the print statement
               to use it which is a GNU extension
            */
            /* */
            "some_text
"
            i * resolution
            j * resolution
            "15.95 cm
"
            /* */
            /* non-POSIX: 
            print "some_text ", i * resolution, " ", j * resolution, " 15.95 cm\n"
            */
        }
    }
}
quit