How to Do Floating Point Math in Linux Bash Scripts

Key Takeaways

  • The Linux Bash shell only supports integer arithmetic and cannot perform calculations on floating point numbers.
  • The bc utility in Linux allows for precision floating point calculations interactively and in shell scripts.
  • Using bc, you can set the number of decimal places to display and perform calculations with arbitrary precision, including using functions from the standard math library.


The Linux Bash shell supports integer arithmetic only. It can neither understand nor cope with floating point calculations. The bc utility gives you precision floating point calculations interactively and in shell scripts.


Why Bash Only Supports Integers

The original design decision to restrict the Unix Bourne shell to integer arithmetic might be rooted in the early-computing mapping of an integer to a single byte of RAM. We may never know what was truly behind the decision. Nor, for that matter, why the Linux version of the Bourne shell, the Bash shell, chose to follow suit.

On its own, Bash cannot perform calculations on floating point numbers, and calculations on integers that would have a fractional part to the answer, are reported as truncated integer values. This is true on the command line and in Bash shell scripts. Depending on your use case, this can be problematic or show-stopping.

Linux comes with two utility applications that allow you to perform floating point calculations. One of these is dc. It’s a bit of a curio, operating as it does in reverse-Polish notation. The other tool is bc. It can be used interactively or as a command, and it’s the solution we’ll discuss here.

Related: 9 Bash Script Examples

The Problem

Let’s get Bash to divide six by three.

 echo $((6 / 3)) 
Dividing two integers with no remainder on the Bash command line

We get our expected answer of two. Now let’s divide six by seven. Clearly, that will have a fractional answer.

 echo $((6 / 7)) 
Dividing two integers on the Bash command line with a fractional remainder. The remainder is never shown.

Zero is obviously wrong. Let’s try again, dividing 16 by 7.

 echo $((16 / 7)) 
Illustraing the issue with BAsh only supporting integer arithmetic by dividing two integers. The fractional remainder is discarded.

We get an answer of two. What’s happening is the fractional part of the answer is being discarded, so the answer is truncated. There was no fractional part in the first example, so we get the correct answer.

The second example had no integer element in the answer, only a fractional part. Because the fractional part has been discarded the answer we’re shown is zero.

In the third example, 7 divides into 16 twice, with a fractional remainder. Again, the remainder is discarded, and the result is truncated.

Using bc Interactively

You can use bc as an interactive calculator by typing bc and pressing the “Enter” key.

 bc 
The bc welcome message and prompt

The bc application launches, announces its version number, and then waits for your input. Typing a calculation and pressing “Enter” causes bc to evaluate the calculation and display the answer.

 16 * 4

1024 / 32

2^2 * 1024

Three example calculations in bc, in interactive mode

You can use “Ctrl+L” to clear the screen, and “Ctrl+D” to exit from the program. Let’s try a calculation that will have a fractional component in the answer.

 22 / 7 
bc defaults to showing no decimal places. Pi is truncated to 3.

That’s not what we expected. Counterintuitively, although bc allows us to use arbitrary precision, by default it won’t display the decimal point nor any figures that follow it.

To make the true answer visible we need to tell bc how many decimal places to display. We do this with the “scale” command. We’ll ask for seven decimal places, and re-do our calculation.

 scale=7
22 / 7
Using scale to tell bc to show up to 7 decimal places in the results of calculations

Finally, we’re getting somewhere. The “scale” setting remains in place until you change it. Setting the number of decimal places tells bc the maximum number of places to display. If an answer doesn’t need that many decimal places, it’s displayed with the number of decimal places it requires and no more. It doesn’t get padded with meaningless zeroes.

 scale=10
0.300003 * 0.5
bc only displays the decimal places it needs. Setting scale to 10 will not force 10 decimal places to be used. If an answer requires fewer decimal places, they're the only ones that are displayted.

You can list different calculations on the same line by using a semicolon “;” to separate them. The answers are displayed on per line as usual, in the order the calculations were listed.

 25 * 6; 12.5 + 45.001; 3 + 5 + 7 + 9 
You can add multiple calculation to a line by separating them with semi-colons.

You can include the “scale” command in the list, too.

 scale=8; 22 / 7; scale=3; 0.3 * 0.071 
You can change the setting of scale for each calculation, even calculations on the same command line

The Standard Math Library

The -l (standard math library) option causes bc to load a set of functions, and sets “scale” to 20 decimal places.

 bc -l
22 / 7
bc launched with the -l option, showing pi calculated to 20 decimal places

With the standard library loaded, you can use these functions in your calculations.

  • s (x): The sine of x
  • c (x): The cosine of x.
  • a (x): The arctangent of x
  • l (x): The natural logarithm of x
  • e (x): The exponential of e to the value x
  • j (n,x): The Bessel function of integer order n of x.

Sine, cosine, and arctangent use radian values.

 s (1.1)
 
c (.891207)
 
a (.628473)
Calculating the sine, cosine, and arctan in bc in interactive mode

Sending Input to bc on the Command Line

You can use redirection and pipes to send input to bc. It processes your input and displays the answer in the terminal window.

You can redirect into bc with or without the -l (standard math library) option.

 bc <<< 22/7
bc -l <<< 22/7
Redirecting input into bc and bc -l

To pipe input to bc, the input has to be the output of another process. It’s convenient to use echo for this.

 echo 22/7 | bc
echo 22/7 | bc -l
Using echo to pipe input into bc and bc -l

If you have spaces in your input, or want to include the “scale” command, wrap your input in quotation marks.

 echo "22 / 7" | bc -l
echo "scale=6; 22 / 7" | bc
Wrapping input that includes spaces in quotation marks to pipe it into bc and bc -l

Using bc in Bash Shell Scripts

We’ve now got all we need to be able to perform floating point calculations in our bash scripts, to our chosen precision. We can also reference Bash variables in our calculations, including parameters to the script.

Here’s our example script. Copy this text into an editor, save it as “pi.sh”, then close your editor.

 #!/bin/bash

first_number=22
second_number=7

pi=$(echo "scale=$1; $first_number/$second_number" | bc)

echo "Pi to $1 decimal places is: $pi"

We use two variables, “first_number” and “second_number” to hold two numerical values. We use those variables in the input that we’re piping into bc.

We’ve also used the first command line parameter passed to the script, “$1”, as the value to set “scale” to.

Before we can try our script, we need to make it executable with chmod.

 chmod +x pi.sh 
Using chmod to make a script executable

Let’s try our script with different command line values.

 ./pi.sh 5
./pi.sh 14
./pi.sh 20
Output from the pi.sh script showing pi calculated to three different precisions

We get pi displayed to number of places we specify on the command line to our script.

Related: How to Use getopts to parse Linux Shell Script Options

It All Adds Up

Moving beyond the limitations of Bash’s integer-only mathematics gives our scripts precision and accuracy.

Using echo to pipe input to bc inside scripts is a little clunky, but it works perfectly well, and the benefits are worth it.

Source

      Guidantech
      Logo
      Shopping cart