Floating-point division in bash - bash

I'm trying to convert whatever numbers the user inputs into 2 decimal places.
For instance
What is the total cost in cents? 2345
output: 23.45
this is the code i have so far
percentage=20 #cannot change numerical value must convert into 0.20
echo -n "What is the total cost? ";
read cost_in_cents
echo "scale 1; $cost_in_cents" | bc
I'm also going to be doing some multiplication with percentage, how can i also convert the percentage into a float (0.20)

awk to the rescue!
you can define your own floating point calculator with awk, e.g.
$ calc() { awk "BEGIN{ printf \"%.2f\n\", $* }"; }
now you can call
$ calc 43*20/100
which will return
8.60

Perhaps it's nostalgia for reverse polish notation desk calculators, but I'd use dc rather than bc here:
dc <<<"2 k $cost_in_cents 100 / p"
Output is, properly, a float (with two digits past the decimal point of precision).
The exact same code, with no changes whatsoever, will work to convert 20 to .20.
See BashFAQ #22 for a full discussion on floating-point math in bash.

Bash itself could not process floats.
It can, however, printf them:
$ printf 'value: %06.2f\n' 23.45
value: 023.45
So, you need an external program to do the math:
$ echo "scale=4;2345/100*20/100" | bc
4.6900
Or, equivalent:
$ bc <<<"scale=4;2345*20/10^4"
4.6900
Then, you can format the float with printf:
$ printf 'result: %06.2f\n' $(bc <<<"scale=4;2345*20/10^4")
result: 004.69
Or you can use a program that can process floats; like awk.

How about this:
read -p "What is the total cost? " input
percent=20
echo "scale=2; $input / 100 * $percent / 100" | bc
# input = 2345 , output = 4.69

Related

addition in bash with decimal using bc

I'm new in bash and i'd like to know why my script doesn t work the way i'd like it work..
I have this bash script:
#!/bin/bash
read n
var=($(cat))
bim=${var[*]}
toto=$(echo $bim | sed 's/ /+/g' | bc)
echo $toto
bobo=$(($toto/$n | bc -l))
echo $bobo | awk '{printf "%.3f\n", $1}'
This is supposed to add up all the values that "cat" has stored in an array and divide the total by the first value that "read" reads. And the result should return me a decimal value of three decimal places. However, it only returns a round number to me when I use bc -l! And when I use awk '{printf% .3f ", $ 1}' it prints .000!
Do you know why?
Thanks
bash only does integer arithmetics and the arithmetic expansion
bobo=$(($toto/$n | bc -l))
will not do what you think. The pipe sign in | bc -l is not a pipe sign. It's a bitwise OR. Broken down:
$toto is interpreted as a variable (as would toto)
$n is interpreted as a variable (as would n)
| is bitwise OR
bc is interpreted as a variable (with the value 0)
- is interpreted as a minus sign (in an arithmetic expression)
l is interpreted as a variable (with the value 0)
So, it becomes $toto/$n | 0 -0 which is the same as the integer division toto/n ($ is not needed for variables in arithmetic expansions).
You could instead use bc for the division too, but you need to set the scale in bc. Here's an example setting it to 3 before performing the division:
bobo=$(echo "scale=3;$toto/$n" | bc)
Note that you don't need to echo this through awk.
Just echo $bobo and you should get the result you want.
Example input:
3
11.3
9
8
Output after having applied the suggested changes:
28.3
9.433

Generate uniform random number in range of floats in bash [duplicate]

This question already has answers here:
Random numbers generation with awk in BASH shell
(3 answers)
Closed 2 years ago.
[SOLVED]
I want to generate a uniform random float number in the range of float numbers in the bash script. range e.g. [3.556,6.563]
basically, I am creating LSH(Latin hypercube sampling) function in bash. There I would like to generate an array as one can do with this python command line.
p = np.random.uniform(low=l_lim, high=u_lim, size=[n]).
sample code :
lhs(){
l_lim=($(seq $1 $2 $(echo $3 - $dif | bc)))
h_lim=($(seq $(echo $1 + $dif | bc) $2 $3))
points=()
for ((i=0;i<$n;i++)) ; do
di=${l_lim[i]}
dj=${h_lim[i]}
echo $di, $dj
p=$(awk -v min=6.50 -v max=8.45 -v seed=$RANDOM 'BEGIN{srand(seed);print min+rand()*int(1000*(max-min)+1)/1000}')
points+=("${p}")
done
}
n=5
a=(3 5)
b=(1 3)
dif=$(div $(echo ${a[1]} - ${a[0]} | bc) $n)
lhs ${a[0]} 0.45 ${a[1]}
echo ${points[#]}
I have tried $RANDOM, awk but it did not work for me. I do not want to use python -c.
Most common rand() implementations at least generate a number in the range [0...1), which is really all you need. You can scale a random number in one range to a number in another using the techniques outlined in the answers to this question, eg:
NewValue = (((OldValue - OldMin) * (NewMax - NewMin)) / (OldMax - OldMin)) + NewMin
For bash you have two choices: integer arithmetic or use a different tool.
Some of your choices for tools that support float arithmetic from the command-line include:
a different shell (eg, zsh)
perl: my $x = $minimum + rand($maximum - $minimum);
ruby: x = min + rand * (max-min)
awk: awk -v min=3 -v max=17 'BEGIN{srand(); print min+rand()*int(1000*(max-min)+1)/1000}'
note: The original answer this was copied from is broken; the above is a slight modification to help correct the problem.
bc: printf '%s\n' $(echo "scale=8; $RANDOM/32768" | bc )
... to name a few.

Why rounding error in bash?

5+50*3/20 + (19*2)/7 = 17.9285714286
= 17.929
I want to get the exact value truncated to 3 decimal places, that is 17.929 by doing the following bash operation.
echo " scale = 3; 5+50*3/20 + (19*2)/7 " | bc
But it gives me the value 17.928.
$ echo " scale = 3; 5+50*3/20 + (10*9)/7 " | bc
17.928
What Can I do??
N.B.: This is a Hackerrank challenge. Even it's not giving correct output in their console.
bc is ceiling the decimal value rather than rounding off. You can use awk:
awk 'BEGIN{printf "%.3f\n", 5+50*3/20 + (19*2)/7}'
17.929
When you use scale=3 in bc, you're not only specifying the number of decimal places in the output, you're limiting the number of decimal places that bc is using to do its calculations.
To get the correct output, use printf with bc:
$ printf '%.3f\n' "$(bc -l <<<'5+50*3/20 + (19*2)/7')"
17.929
If the expression is inside a variable $var, replace the string in single quotes with "$var".

How to round a floating point number upto 3 digits after decimal point in bash

I am a new bash learner. I want to print the result of an expression given as input having 3 digits after decimal point with rounding if needed.
I can use the following code, but it does not round. Say if I give 5+50*3/20 + (19*2)/7 as input for the following code, the given output is 17.928. Actual result is 17.92857.... So, it is truncating instead of rounding. I want to round it, that means the output should be 17.929. My code:
read a
echo "scale = 3; $a" | bc -l
Equivalent C++ code can be(in main function):
float a = 5+50*3.0/20.0 + (19*2.0)/7.0;
cout<<setprecision(3)<<fixed<<a<<endl;
What about
a=`echo "5+50*3/20 + (19*2)/7" | bc -l`
a_rounded=`printf "%.3f" $a`
echo "a = $a"
echo "a_rounded = $a_rounded"
which outputs
a = 17.92857142857142857142
a_rounded = 17.929
?
You can use awk:
awk 'BEGIN{printf "%.3f\n", (5+50*3/20 + (19*2)/7)}'
17.929
%.3f output format will round up the number to 3 decimal points.
Try using this:
Here bc will provide the bash the functionality of caluculator and -l will read every single one in string and finally we are printing only three decimals at end
read num
echo $num | bc -l | xargs printf "%.3f"

Bash Multiplying Decimal to int

I read price from user input. When i multiply the input with int like this
T="$((PRICE*QTY))"|bc; gives
line 272: 12.00: syntax error: invalid arithmetic operator (error token is ".00")
or .50
depending on user input. How do i multiply these two variables and get a total with 2 decimal points?
this works:
PRICE=1.1
QTY=21
RES=$(echo "scale=4; $PRICE*$QTY" | bc)
echo $RES
var=$(echo "scale=2;$PRICE*$QTY" |bc)
You can also use awk
awk -vp=$PRICE -vq=$QTY 'BEGIN{printf "%.2f" ,p * q}'
T="$(echo "$PRICE*$QTY" | bc)"
You can use
mul=0.8
exp=200
texp=awk -vp=$mul -vq=$exp 'BEGIN{printf "%.2f" ,p * q}'
Hope this is going to work.
First, trying to do floating-point arithmetic with bc(1) without using the -l flag is bound to give you some funny answers:
sarnold#haig:~$ bc -q
3.5 * 3.5
12.2
sarnold#haig:~$ bc -q -l
3.5 * 3.5
12.25
Second, the $((...)) is an attempt to do arithmetic in your shell; neither my bash nor dash can handle floating point numbers.
If you want to do the arithmetic in your shell, note printf(1) as well as (probably) your shell's built-in printf function. If you want to do the arithmetic in bc, note the special variable scale.

Resources