web-dev-qa-db-ja.com

bcに後続ゼロを出力させるには?

私はbcに最初のゼロを出力させる方法についてのトピックを読みましたが、それは私が望んでいるものとは正確には異なります。私がもっと欲しい...

10進数8桁の浮動小数点数を返す関数が必要です。私は、awkを使用するか、公平であることを何でも使用して、任意の解決策を受け入れます。例は私が何を意味するかを説明します:

hypothenuse () {
        local a=${1}
        local b=${2}
        echo "This is a ${a} and b ${b}"
        local x=`echo "scale=8; $a^2" | bc -l`
        local y=`echo "scale=8; $b^2" | bc -l`
        echo "This is x ${x} and y ${y}"
#       local sum=`awk -v k=$x -v k=$y 'BEGIN {print (k + l)}'`
#       echo "This is sum ${sum}"
        local c=`echo "scale=8; sqrt($a^2 + $b^2)" | bc -l`
        echo "This is c ${c}"
}

時々、ab0.00000000、そしてcが返されたときにこれらすべての0を保持する必要があります。現在、これが発生すると、このコードは次の出力を返します。

This is a 0.00000000 and b 0.00000000
This is x 0 and y 0
This is c 0

そして、私はそれを印刷したいです

This is a 0.00000000 and b 0.00000000
This is x 0.00000000 and y 0.00000000
This is c 0.00000000

助けていただければ幸いです!

4
Clement S

BCでは、解決策は1で除算することです。

_$ bc -l <<<"scale=8; x=25*20; x"
500

$ bc -l <<<"scale=8; x=25*20; x/1"
500.00000000
_

したがって、スクリプトは次のようになります。

_hypothenuse () {
        local a b c x y
        a=${1}; b=${2}
        echo "This is a ${a} and b ${b}"
        x=$(echo "scale=8; $a^2/1" | bc -l)
        y=$(echo "scale=8; $b^2/1" | bc -l)
        echo "This is x ${x} and y ${y}"
#       local sum=`awk -v k=$x -v k=$y 'BEGIN {print (k + l)}'`
#       echo "This is sum ${sum}"
        c=$(echo "scale=8; sqrt($a^2 + $b^2)/1" | bc -l)
        echo "This is c ${c}"
}
_

_`…`_の代わりに$(…)を使用することを強くお勧めします。

しかし、それでも0の値で失敗します。

最善の解決策は、bcのスケールを(bc -lから)20にし、bcへの1回の呼び出しで必要なすべての計算を行い、必要に応じてprintfで出力をフォーマットすることです。はいprintfは浮動小数点数をフォーマットできます。

Bashを想定

_hypothenuse () {  local a b c x y
                  a=${1:-0} b=${2:-0}
                  read -d '' x y c < <(
                  bc -l <<<"a=$a; b=$b; x=a^2; y=b^2; c=sqrt(x+y); x;y;c"
                  )

                  printf 'This is a %14.8f and b %14.8f\n' "$a" "$b"
                  printf 'This is x %14.8f and y %14.8f\n' "$x" "$y"
                  printf 'This is c %14.8f             \n' "$c"
               }
_
10
Isaac

printfを使用して、この方法でフォーマットを外部化できます。

printf "%0.8f" ${x}

例:

x=3
printf "%0.8f\n" ${x}
3.00000000

注:printf出力は、ロケール設定によって異なります。

6
Amessihel

Awkを使用するだけです。

$ cat tst.sh
#!/bin/env bash

hypothenuse() {
    awk -v a="$1" -v b="$2" 'BEGIN {
        printf "This is a %0.8f and b %0.8f\n", a, b
        c = sqrt(a^2 + b^2)
        printf "This is c %0.8f\n", c
    }'
}

hypothenuse "$@"

$ ./tst.sh 0 0
This is a 0.00000000 and b 0.00000000
This is c 0.00000000

$ ./tst.sh 17.12 23.567
This is a 17.12000000 and b 23.56700000
This is c 29.12898709
3
Ed Morton

あなたの質問は少し曖昧です。あなたは「…これらすべての0を保持する必要がある…」と言います。 8桁の10進数で出力を取得する方法を説明した人もいます。しかし、入力値abがすでに持っている10進数を動的に決定しますか(同じ精度でcを出力できます)?

これは内部的にbashで行うことができます:

_a_digits=0
if [[ $a =~ \.([0-9]*)$ ]]
then
        a_digits="${#BASH_REMATCH[1]}"
fi
b_digits=0
if [[ $b =~ \.([0-9]*)$ ]]
then
        b_digits="${#BASH_REMATCH[1]}"
fi
_

_=~_は、文字列を正規表現と比較します。正規表現\.([0-9]*)$_._に一致し、その後に文字列の最後に一連の数字が続き、グループ内の数字のシーケンスが続きます。 _BASH_REMATCH_は、正規表現全体とキャプチャグループ(存在する場合)の一致を含む配列です。したがって、aが_3.1416_の場合、_BASH_REMATCH[1]_は_1416_になります。次に、_a_digits_はその長さ、つまり_4_を取得します。

Bashがない場合は、exprコマンドを使用して同じことを行うことができます。

_a_digits=$( expr length '(' "$a" : '.*\.\([0-9]*\)$' ')' )
b_digits=$( expr length '(' "$b" : '.*\.\([0-9]*\)$' ')' )
_

これはまったく同じロジックです。

次に、より大きな(最大の)値を取得できます。

_if [ "$a_digits" -gt "$b_digits" ]
then
        digits="$a_digits"
else
        digits="$b_digits"
fi
_

または逆に、より小さな(最小)値を取得します。

次に、この動的に決定された精度を他のソリューションで使用できます。

_printf "%0.${digits}f\n" "$c"
_

または

_printf '%0.*f\n' "$digits" "$c"
_

または

_…scale=$digits; …
_