bash float number

dealing with float numbers in bash

Dealing with float numbers in bash can be a bit tricky since bash natively supports only integer arithmetic. However, you can perform floating-point arithmetic using external tools. Here we will walk through few methods to handle floating-point numbers in bash.

When dealing with integers, all is simple. See this example:

[root@linux ~]# echo $((2+2))
4
[root@linux ~]# x=2; y=3
[root@linux ~]# echo $((x+y))
5
[root@linux ~]#

However, when it comes to float numbers, this approach wouldn’t work. You need to invoke some external command which would be able to process float numbers and perform arithmetic operations with them. As in any other case, *nix world has many different solutions for the same problem, and float calculations is not an exception. You can use bc, awk, dc, perl, python

bc

I personally prefer bc over anything else. It is designed exactly for the purpose of calculations, so why not use it? The only disadvantage which I noticed is that in some cases it might be slower than awk.

[root@linux ~]# echo "3.5 * 2.12345" | bc
7.43207
[root@linux ~]#
[root@linux ~]# echo "scale=4; 1 / 3" | bc
.3333
[root@linux ~]#

Small thing worth to mention here is leading zero, which is missing. To fix it, you can use printf like:

[root@linux ~]# printf "%.4f\n" "$(echo "scale=4; 1 / 3" | bc)"
0.3333
[root@linux ~]#

awk

While awk can perform arithmetic operations, its primary strength lies in text processing. If your script needs to combine text processing with arithmetic, awk can be more convenient.

[root@linux ~]# awk 'BEGIN {print 3.5 + 2.11}'
5.61
[root@linux ~]#

Benchmark testing of bash float number operations

Finally, we can perform some benchmark tests. Here is the script which you can try yourself and choose whatever suits you best:

#!/bin/bash

iterations=10000

echo "Using bc:"
time for i in $(seq 1 $iterations); do
  result=$(echo "3.5 * 2.1" | bc)
done

echo ""

echo "Using awk:"
time for i in $(seq 1 $iterations); do
  result=$(awk 'BEGIN {print 3.5 * 2.1}')
done

echo ""

echo "Using python:"
time for i in $(seq 1 $iterations); do
  result=$(python -c "print(3.5 * 2.1)")
done

echo ""

echo "Using perl:"
time for i in $(seq 1 $iterations); do
  result=$(perl -e 'print 3.5 * 2.1')
done

echo ""

echo "Using dc:"
time for i in $(seq 1 $iterations); do
  result=$(echo "3.5 2.1 * p" | dc)
done

exit 0

Expected results are the following:

awk: generally performs well and is often faster than bc for simple arithmetic operations
bc: has some overhead due to its precision and capability but performs adequately for complex arithmetic
python: it has a significant startup time, making it slower for a large number of simple calculations
perl: similar to python, perl has startup overhead
dc: dc is designed for arbitrary-precision arithmetic and can be efficient, but its usage is less common

Let’s run the test:

[root@linux ~]# ./float.sh
Using bc:

real    0m18.733s
user    0m10.671s
sys     0m11.763s

Using awk:

real    0m14.815s
user    0m5.192s
sys     0m9.593s

Using python:

real    1m55.394s
user    1m16.351s
sys     0m38.699s

Using perl:

real    0m26.210s
user    0m11.537s
sys     0m14.863s

Using dc:

real    0m16.044s
user    0m11.055s
sys     0m8.567s
[root@linux ~]#

Summary

The decision to not support floating-point arithmetic natively in bash is rooted in historical context, design philosophy, and practical considerations. Bash is designed to be a lightweight, efficient scripting environment for command execution and text processing, with the ability to leverage external tools for more complex tasks. This approach aligns with the Unix philosophy of using specialized tools for specific tasks, maintaining simplicity, and ensuring performance.

However, by employing additional external tools you can easily perform arithmetic operations with float numbers in bash and incorporate it easily into your scripts.