50

I would like to do the following operation in my script:

1 - ((m - 20) / 34) 

I would like to assign the result of this operation to another variable. I want my script use floating point math. For example, for m = 34:

results = 1 - ((34 - 20) / 34) == 0.588 

7 Answers 7

61

You could use the bc calculator. It will do arbitrary precision math using decimals (not binary floating point) if you set increease scale from its default of 0:

$ m=34 $ bc <<< "scale = 10; 1 - (($m - 20) / 34)" .5882352942 

The -l option will load the standard math library and default the scale to 20:

$ bc -l <<< "1 - (($m - 20) / 34)" .58823529411764705883 

You can then use printf to format the output, if you so choose:

printf "%.3f\n" "$(bc -l ...)" 
Sign up to request clarification or add additional context in comments.

2 Comments

@rubo77 I did something like this let fail_percent=0 let total=$((pass_count+fail_count)) printf "Fail percentage is %f\n" $(bc -l <<< "($fail_count / $total)") here the total=16 and fail_count=15, I get the answer as .93750000000000000000, but it comes with an error as printf invalid number I have given #!/bin/bash in the script beginning... ANy idea why the error ?
using printf '%f\n' $(bc -l <<< 1.2) I get the error bash: printf: 1.2: Ungültige Zahl.
27

Bash does not do floating point math. You can use awk or bc to handle this. Here is an awk example:

$ m=34; awk -v m=$m 'BEGIN { print 1 - ((m - 20) / 34) }' 0.588235 

To assign the output to a variable:

var=$(awk -v m=$m 'BEGIN { print 1 - ((m - 20) / 34) }') 

1 Comment

This worked great for me. I changed it slightly because the awk script is so simple, you don't need to protect it with single quotes. Here's a slightly simpler version: $ m=34; awk "BEGIN { print 1 - (($m - 20) / 34) }". I simply changed single quotes to double quotes so bash will interpolate the $m for me.
20

Teach bash e.g. integer division with floating point results:

#!/bin/bash div () # Arguments: dividend and divisor { if [ $2 -eq 0 ]; then echo division by 0; return 1; fi local p=12 # precision local c=${c:-0} # precision counter local d=. # decimal separator local r=$(($1/$2)); echo -n $r # result of division local m=$(($r*$2)) [ $c -eq 0 ] && [ $m -ne $1 ] && echo -n $d [ $1 -eq $m ] || [ $c -eq $p ] && echo && return local e=$(($1-$m)) c=$(($c+1)) div $(($e*10)) $2 } result=$(div 1080 633) # write to variable echo $result result=$(div 7 34) echo $result result=$(div 8 32) echo $result result=$(div 246891510 2) echo $result result=$(div 5000000 177) echo $result 

Output:

 1.706161137440 0.205882352941 0.25 123445755 28248.587570621468 

1 Comment

Very nice. This would even be POSIX-compliant if the let c=c+1 were changed to c=$(($c+1)), but that recursion looks expensive...
10
echo $a/$b|bc -l 

gives the result.

Example:

read a b echo $a/$b|bc -l 

Enter a & b value as 10 3, you get 3.3333333333

If you want to store the value in another variable then use the code

read a b c=`echo $a/$b|bc -l` echo $c 

It also gives the same result as above. Try it...

Comments

1

I know this is an old thread, but this seemed like a fun project to tackle without using bc or invoking recursion. I'm sure it can be improved, but this maxed out my skill.

numerator=5 denominator=7 # - 0 -> returns "undef" decimal_places=4 # - 0 -> same as echo $(( $numerator / $denominator )) _result_sign="" let _dp_exp=10**decimal_places if [ $denominator -eq 0 ]; then _div_result_int_large=0; else let _div_result_int_large=$((numerator * _dp_exp / denominator)); fi if [ $_div_result_int_large -lt 0 ]; then let _div_result_int_large=$(( _div_result_int_large * -1 )); _result_sign="-"; fi let _div_result_int=$((_div_result_int_large / _dp_exp)) let _div_result_mant=$((_div_result_int_large - _div_result_int * _dp_exp)) let _dp_lzeros=$((decimal_places - ${#_div_result_mant})) printf -v _div_result_mant_padded "%.${_dp_lzeros}d$_div_result_mant" div_result="$_result_sign$_div_result_int" if [ $decimal_places -gt 0 ]; then div_result="$_result_sign$_div_result_int.$_div_result_mant_padded"; fi if [ $denominator -eq 0 ]; then div_result="undef"; fi echo $div_result 

Example output:

numerator=5 denominator=7 decimal_places=5 -> 0.71428 numerator=250 denominator=13 decimal_places=0 -> 19 numerator=-5 denominator=6 decimal_places=2 -> -0.83 numerator=3 denominator=0 # - uh-oh decimal_places=2 # - can be anything, in this case -> undef 

Comments

0

Just to note that many times you actually don’t need floating point arithmetic. For example, instead of

results = 1 - ((34 - 20) / 34) == 0.588 

you can always write

results = 1000 - (((34 - 20) * 1000) / 34) == 588 

which is the equivalent.

Comments

-1

Use this script open this file with favorite editor like:

$ sudo vim /usr/bin/div 

Then paste this code:

#!/bin/bash # Author: Danial Rikhteh Garan ([email protected]) if [[ -z "$1" ]] || [[ -z "$2" ]]; then echo "Please input two number" echo "for 100/50 use: div 10 50" exit 1; fi div=$(echo "$1/$2" | bc -l); echo 0$div | sed 's/[0]*$//g' 

Now chmod it to 755:

$ sudo chmod 755 /usr/bin/div 

Now use it:

$ div 5 100 0.05 

In your script you can use this:

var=$(div 5 100); echo "$var" 

Comments