如何让 bc 打印尾随零?

如何让 bc 打印尾随零?

我阅读了有关如何让 bc 打印第一个零的主题,但这并不是我想要的。我想要更多...

我想要一个返回具有八位小数的浮点数的函数。我对任何解决方案持开放态度,使用 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

非常感谢您的帮助!

答案1

在 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 的小数位数为 20(来自 bc -l),在一次调用 bc 中完成所需的所有数学计算,然后根据需要格式化输出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"
               }

答案2

您可以使用以下方式外部化格式printf

printf "%0.8f" ${x}

例子:

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

注意:printf输出取决于您的区域设置。

答案3

只需使用 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

答案4

你的问题有点模棱两可。你说“……我需要保留所有这些 0……”。其他人已经告诉您如何获得八位十进制数字的输出。但是,您是否想动态确定输入值已经有多少位十进制数字a( b以便可以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是一个数组,其中包含整个正则表达式和捕获组(如果有)的匹配项。所以,如果 a3.1416BASH_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; …

相关内容