0

I use qalculate as my day-to-day calculator and it's great! It is easy enough to type in something like:

(1+10^(-17.2/20)) / (1-10^(-17.2/20))

and get the right answer:

1.320289

But trying to get bc to do this sort of calculation in a bash script is frustrating. Google search spits back many pages demonstrating the simplest kinds of simple math examples using bc, but I have yet to find any pages tackling how to perform more complex calculations. When I type the following at CL:

echo 'scale=50; (1+10^(-17.2/20)) / (1-10^(-17.2/20))' | bc -l

I get the following warning-errors:

Runtime warning (func=(main), adr=25): non-zero scale in exponent
Runtime warning (func=(main), adr=44): non-zero scale in exponent
Runtime error (func=(main), adr=46): Divide by zero

If I try something similar but a little simpler like:

echo '(1-10^(-17.2/20))' | bc -l

I do get an answer, buts it's wrong and comes complete with a warning.

Runtime warning (func=(main), adr=18): non-zero scale in exponent
0

What could bc be having trouble with here, or rather what am I not doing correctly to get bc to perform these calculations properly?

scriptz
  • 515
  • 2
  • 10

2 Answers2

3

Unfortunately, bc doesn't support exponents such as -17.2/20. If you don't require 50 decimal places of precision, one option would be to use another tool such as awk:

$ awk 'BEGIN{print (1+10^(-17.2/20)) / (1-10^(-17.2/20))}'
1.32029

You can pass variables to awk from your script like this:

$ awk -va="-17.2" -vb="20" 'BEGIN{print (1+10^(a/b)) / (1-10^(a/b))}'
1.32029
Tom Fenech
  • 72,334
  • 12
  • 107
  • 141
  • I need to do something like: `awk -va="$1" 'BEGIN{print (1+10^(a/20)) / (1-10^(a/20))}'` to make a .bashrc alias that uses value of var $1 provided by user when command is typed in at terminal. This, however, only returns the value `inf` no matter what I provide as var $1. If I can get this to work then no need for a script to do the same. – scriptz Jan 20 '15 at 00:27
  • works fine calling user input $1 in bash script, but I still think an alias would be more efficient. – scriptz Jan 20 '15 at 12:00
  • @scriptz, You can use function instead of alias: function test() { awk -va=$1 -vb=$2 'BEGIN{print (1+10^(a/b)) / (1-10^(a/b))}'; } – Udi May 18 '16 at 17:02
3

from the bc man page:

expr ^ expr: The result of the expression is the value of the first raised to the second. The second expression must be an integer.

but since if x = a^b, then ln(x) = ln(a^b) = b(ln(a)), we can see that x = exp(b(ln(a))), so if you want to raise things to fractional b's you can use that.

Note: In bc the actual exp and ln functions are e and l.

genisage
  • 1,159
  • 7
  • 17
  • 2
    producing: `echo 'a=10; b=-17.2/20; x=e(b*l(a)); (1+x)/(1-x)' | bc -l` – glenn jackman Jan 19 '15 at 22:40
  • 1
    I am sure there are very valid reasons for the way bc requires its calculations to be entered, but compared with the `awk` solution provided below, the bc way for entering calculations does not read or feel very intuitive, but rather opaque and awkward. An already complex calculation has been rendered even more difficult to follow. Unless there are any serious drawbacks using `awk` for complex calculations it looks like the hands down winner between the two. – scriptz Jan 20 '15 at 00:02
  • 1
    @scriptz the advantage bc has is that it can be arbitrarily precise. If you don't need that, the `awk` solution is probably superior. – genisage Jan 20 '15 at 00:15