Floating point numbers in bash

5,906

Solution 1

bash does not do floating-point arithmetic, but rather fixed-point, where the decimal is fixed at zero places (i. e. integer maths). This means that you can work around it for some very very basic computation:

$ a=1;b=3
$ echo $(( (a*1000 / b ) ))
333

So, 1/3 to three places is .333.

This is a bad idea; don't do this.

There are many ways to do FP maths on the command line. Here are just two examples:

$ python -c 'print( 1.0 / 3 )'
0.333333333333
$ echo 'scale=3; 1.0/3' | bc
.333

Solution 2

bash cannot do decimal point mathematical operations, only integer operations

robert@pip2:/tmp$ echo $((2 * 3))
6
robert@pip2:/tmp$ echo $((2 * 3.5))
bash: 2 * 3.5: syntax error: invalid arithmetic operator (error token is ".5")
robert@pip2:/tmp$ 

Solution 3

Yes, like dash, bash is limited to integer arithmetic math in $((…)).
In fact, by default, all shells (default POSIX) will print 37 with this:

$ echo "$((1000/27))"
37

From [POSIX][1]:

Only signed long integer arithmetic is required.

You need to change the numbers a bit to get floating point math in ksh, zsh, and yash (not jsh, dash, ash, lksh, mksh and bash):

$ echo $((1000/27.0))
37.037037037037037

But be careful with zsh precedence and precision:

$ for sh in ksh yash zsh; do $sh -c 'printf "%20d\n" "$(( 1<<63 - 5))"'; done
  288230376151711744
  288230376151711744
 9223372036854775803

$ for sh in ksh yash zsh; do $sh -c 'printf "%-20s\n" "$((1/10.0))"'; done
0.1                 
0.1                 
0.10000000000000001

Unexpected zsh truncation limits:

$ zsh -c 'echo $((12345678901234567890));echo $((12345678901234567890123))'

zsh:1: number truncated after 19 digits: 12345678901234567890
1234567890123456789

zsh:1: number truncated after 22 digits: 12345678901234567890123
-1363962815083169260

There is a workaround in bash using printf capabilities (limited to ~10 digits):

$ bash -c 'printf "%.10f\n" "$(( 10**10*  1000/27  ))e-10"'
37.0370370370

But why bother having bc available:

$ echo '1000/27' | bc -l
37.03703703703703703703

[1]: Only signed long integer arithmetic is required.

Solution 4

Not using bash specifically, but you should have bc available to you:

# bc doesn't like exponential numbers in the manner provided.  It can be done, but this number is equivalent.
x=2.8026407
printf "1000 * %s" "$x" | bc
Share:
5,906

Related videos on Youtube

pfnuesel
Author by

pfnuesel

Updated on September 18, 2022

Comments

  • pfnuesel
    pfnuesel over 1 year

    Let's say I have a variable and I want to print 5 significant digits after I multiplied it by 1000. zsh can do it:

    zsh$ x=2.8026407e+00
    zsh$ printf "%.5g\n" "$(( 1000*${x} ))"
    zsh> 2802.6
    

    Can bash do it as well?

    bash$ x=2.8026407e+00
    bash$ printf "%.5g\n" "$(( 1000*${x} ))"
    bash> bash: 1000*2.8026407e+00 : syntax error: invalid arithmetic operator (error token is ".8026407e+00 ")
    

    I think there is no way to make native bash understand floating point operations, is there? I know I can use e.g. awk, but I was wondering if bash could do this at all or not.

    (I'm not surprised that bash cannot handle floats, but that zsh can!)