# How to get bc to print trailing zeros?

I read topics about how to get bc to print the first zero, but that is not exactly what I want. I want more...

I want a function that returns floating point numbers with eight decimal digits. I am open to any solutions, using awk or whatever to be fair. An example will illustrate what I mean:

``````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}"
}
``````

Sometime, `a` and `b` are `0.00000000`, and I need to keep all these 0s when `c` is returned. Currently, when this happens, this code give back the following output:

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

And I would like it to print

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

Help will be much appreciated!

You can externalize formatting this way, using `printf`:

``````printf "%0.8f" \${x}
``````

Example:

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

Note: `printf` output depends on your locale settings.

In bc, the solution is to divide by 1:

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

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

So, your script could be like this:

``````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}"
}
``````

I strongly suggest that you use `\$(…)` instead of ``…``.

But even that fails with values of 0.

The best solution is to let the scale of bc be 20 (from bc -l), make all the math required in one call to bc and then format the output as required with `printf`. Yes `printf` could format floats.

Assuming 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"
}
``````
• Seems better than my solution, since it doesn't require an additional command call. Wish bc didn't require a division by 1 though. – Amessihel Jan 7 '20 at 19:21
• Thank you very much, both for the fast answer, and the precision of it! The only thing is, what does `-0` do in `a=\${1:-0}` ? – Clement S Jan 8 '20 at 9:59
• @ClementSoulie, `-0` stands for "affect `0` if `\$1` is empty" – Amessihel Jan 8 '20 at 10:25
• Awesome, Thanks !! – Clement S Jan 8 '20 at 11:16

Just use 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
``````

Your question is a little ambiguous.  You say “… I need to keep all these 0s …”.  Others have told you how to get output with eight decimal digits.  But, do you want to determine dynamically how many decimal digits the input values `a` and `b` already have (so you can output `c` with the same precision)?

You can do this internally in bash:

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

`=~` compares a string to a regular expression.  The regular expression `\.([0-9]*)\$` matches a `.` followed by a sequence of digits at the end of the string, with the sequence of digits in a group.  `BASH_REMATCH` is an array that contains the match for the entire regex and the capture groups (if any).  So, if `a` is `3.1416`, `BASH_REMATCH` is `1416`.  Then `a_digits` gets the length of that, which is `4`.

If you don’t have bash, you can do the same thing with the `expr` command:

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

which is the exact same logic.

You can then get the larger (maximum) value:

``````if [ "\$a_digits" -gt "\$b_digits" ]
then
digits="\$a_digits"
else
digits="\$b_digits"
fi
``````

or the reverse, to get the smaller (minimum) value.

You can then use this dynamically determined precision in the other solutions:

``````printf "%0.\${digits}f\n" "\$c"
``````

or

``````printf '%0.*f\n' "\$digits" "\$c"
``````

or

``````…scale=\$digits; …
``````