开发者

More simple math help in bash!

In the same thread as this question, I am giving this another shot and ask SO to help address how I should take care of this problem. I'm writing a bash script which needs to perform the following:

  1. I have a circle in x and y with radius r.
  2. I s开发者_开发问答pecify resolution which is the distance between points I'm checking.
  3. I need to loop over x and y (from -r to r) and check if the current (x,y) is in the circle, but I loop over discrete i and j instead.
  4. Then i and j need to go from -r/resolution to +r/resolution.
  5. In the loop, what will need to happen is echo "some_text i*resolution j*resolution 15.95 cm" (note lack of $'s because I'm clueless). This output is what I'm really looking for.

My best shot so far:

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 

I've had just about enough with bash and may look into ksh like was suggested by someone in my last question, but if anyone knows a proper way to execute this, please let me know! What ever the solution to this, it will set my future temperament towards bash scripting for sure.


You may want to include the pipe into bc in the $()'s. Instead of.

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

use

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

should help a bit.

EDIT And here's a solution.

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


As already mentioned this problem is probably best solved using bc, awk, ksh or another scripting language.

Pure Bash. Simple problems which actually need floating point arithmetic sometimes can be transposed to some sort of fixed point arithmetic using only integers. The following solution simulates 2 decimal places after the decimal point. There is no need for pipes and external processes inside the loops if this precision is sufficient.

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))"


you haven't heard of (g)awk ??. then you should go learn about it. It will benefit you for the long run. Translation of your bash script to 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 ......"
            }
        }    
    }
}'


It's looking more like a bc script than a Bash one any way, so here goes:

#!/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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜