DeltaIV DeltaIV - 6 months ago 10
Bash Question

In script, calculate floating point with high precision, and store in shell variable value with a lower precision

In a script of mine, I compute a variable

mflow
from another variable
folder
. The computation must be performed at high accuracy, but then the final result must be truncated to one significant digit. Currently I'm doing this:

#!/bin/bash


for folder in 100 115 116 117; do

temp=$(bc <<< "scale=20;$folder/100*14.8")
mflow=$(bc <<< "scale=1;$temp*1/1")

echo $mflow

done

exit 0


It works fine. However, line

mflow=$(bc <<< "scale=1;$temp*1/1")


seems a bit of a waste. Is there a way to perform the intermediate computations at high accuracy, AND assign the result to
mflow
with a chosen (lower) accuracy? Of course, I don't want to sacrifice the readability of the script too much. Thus, please, not a solution that looks like one of those
sed
"one-liners from hell" ;) (ok, I guess
sed
couldn't be used for this, but you got my point).

PS in case someone wonders why I don't just write

mflow=$(bc <<< "scale=1;$folder/100*14.8")


just try that modification in the script and see what happens (the last three values of
mflow
become equal, which creates issues down the script workflow).

Answer

You can make use of awk for the calculation and output formatting:

for folder in 100 115 116 117; do
        awk -v f="$folder" 'BEGIN{printf "%.1f\n", f/100*14.8}'
done

Thus, it gives:

14.8
17.0
17.2
17.3

If you want to have more precise result printed, you could change %.1f into %.20f, then you have:

14.80000000000000071054
17.01999999999999957367
17.16799999999999926104
17.31599999999999894840

Note:

If you picked bc, you should know this "feature":

kent$  echo "scale=1;17.17777/1"|bc  
17.1

It will give you 17.1 instead of 17.2. I hope you knew this before picking bc as your tool.