Floating point numbers in bash
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
Related videos on Youtube
pfnuesel
Updated on September 18, 2022Comments
-
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 ifbash
could do this at all or not.(I'm not surprised that
bash
cannot handle floats, but thatzsh
can!)