This question already has answers here:
How do I use floating-point arithmetic in bash?
(23 answers)
Closed 4 years ago.
I was taking a challenge on hackerrank .
The aim is:
read (int) N; then read N integers and print their avg to three decimal places.
Here's the code:
#!/bin/bash
#file name:rdlp.sh
read N
s=0
i=1
while (($i<=$N))
do
read a
s=$((s+a))
i=$((i+1))
done
s=$s/$N
echo "scale=3;$s"|bc -l
fi
When I run the code for some inputs:
3 #(value of N)
4 #(N = 3 integers)
4
3
Then the output is 3.666, but it should be 3.667.
So the QUESTION is that is there anyway to get it right (correct rounding off), or does it work like that only?
(the question came off when the above code was run for Testcase2 of the challenge at hackerrank)
bc rounds down with scale=x.
You can printf:
$ printf "%.3f\n" $(echo "scale=1000; 11/3"|bc -l)
3.667
or some tricky bc by adding 0.0005:
$ echo "scale=1000; v=11/3; v=v+0.0005; scale=3; v/1" | bc -l
3.667
Related
This question already has answers here:
Command not found error in Bash variable assignment
(5 answers)
What is the rationale behind variable assignment without space in bash script
(4 answers)
How to retrieve a character in a string at a index in bash [duplicate]
(2 answers)
Closed 29 days ago.
i need help with shell bash. I'm running it on ubuntu virtual machine
My task is this
# A three-digit number is given. Calculate the value of the second digit in the number.
# For example,𝑥 = 456 → 𝑦 = 5.
Here is what i have so far
read -r -p "enter the number" num
while (( $num > 0 )) ; do
digit = "$((num % 10))"
num ="$(( num / 10 ))"
printf "num=%d digit=%d\n" "${num}" "${digit}"
done
Please tell me how i should expand my code so that it actually works ,
By the way the task is to calculate the digit with loops
So doing it this way is no good even though its easier
read -r -p "enter the number: " num
printf "%s\n" "${num:1:1}"
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.
This question already has answers here:
How do I use floating-point arithmetic in bash?
(23 answers)
Closed 2 years ago.
I am trying to collect the data from a string of like "2.0 / 3.0".But when I try the following I get an error.
for i in t01 t02 t03 t04 t05 t06 t07 t08 t09 t10 t11; do
if [ -e "$i/feedback.txt" ]; then
grade=`tail -1 $i/feedback.txt | tr -d [:blank:]`
if [[ $grade =~ ^[0-9]+\.?[0-9]*/[0-9]+\.?[0-9]*$ ]]; then
IFS='/' read -ra grArray <<< "$grade"
score=${grArray[0]}
max=${grArray[1]}
total_tmax=$total_tmax+$max
total_t=$total_t+$score
echo $i: $score / $max
else
echo $i: 0 / 0
Output
t01: 4 / 4
t02: 2 / 3
t03: 3 / 3
t04: 3 / 3
t02/pp_marks.sh: line 39: 13+3.0: syntax error: invalid arithmetic operator (error token is ".0")
As per comments, bash does not allow floating point arithmetic, only integer. For simple tasks, you can use the bc tool (for more complex operation, consider using a scripting engine like awk, python or perl). Note that with bc you have to specify the precision.
total_tmax=$(bc <<<"scale=1 ; $total_tmax+$max")
total_t=$(bc <<< "scale=1 ; $total_t+$score")
echo "$i: $score / $max"
See Also: How do I use floating-point division in bash?
This question already has answers here:
How do I use floating-point arithmetic in bash?
(23 answers)
Closed 4 years ago.
I am attempting to find the sum of a list of numbers' reciprocals. To illustrate what I am trying to do, here's a basic example:
With the file:
1
2
3
4
I would be trying to find the sum of 1/1, 1/2, 1/3 and 1/4. Is there a simple bash one-liner to do this? (I am new to bash, so explanations would be welcome!)
You could do something like this:
sed 's|^|1/|' file | paste -sd+ | bc -l
sed 's|^|1/|' prepends 1/ to every line
paste -sd+ joins all lines with a plus sign creating an arithmetic expression 1/1+1/2+1/3+1/4
bc -l evaluates that arithmetic expression and outputs the result
If you're looking for an arithmetical progression, you can use this bash one-liner using the bc command
d=0; for c in {1..4}; do d=`echo "$d + 1/$c" | bc -l`; done; echo "$d"
Its output is 1 + 0.5 + 0.3333 + 0.25 =
2.08333333333333333333
It works by
Setting a variable named d to 0
Creating a for loop that counts from 1 to 4
In the for loop it sets the d variable to the new value $d + 1/$c passed to the bc -l command executing the arithmetic
And outputs the value with an echo command
This question already has answers here:
Random number from a range in a Bash Script
(19 answers)
Closed 7 years ago.
How would I generate an inclusive random number between 1 to 10 in Bash Shell Script?
Would it be $(RANDOM 1+10)?
$(( ( RANDOM % 10 ) + 1 ))
EDIT. Changed brackets into parenthesis according to the comment.
http://web.archive.org/web/20150206070451/http://islandlinux.org/howto/generate-random-numbers-bash-scripting
Simplest solution would be to use tool which allows you to directly specify ranges, like gnu shuf
shuf -i1-10 -n1
If you want to use $RANDOM, it would be more precise to throw out the last 8 numbers in 0...32767, and just treat it as 0...32759, since taking 0...32767 mod 10 you get the following distribution
0-8 each: 3277
8-9 each: 3276
So, slightly slower but more precise would be
while :; do ran=$RANDOM; ((ran < 32760)) && echo $(((ran%10)+1)) && break; done
To generate random numbers with bash use the $RANDOM internal Bash function. Note that $RANDOM should not be used to generate an encryption key. $RANDOM is generated by using your current process ID (PID) and the current time/date as defined by the number of seconds elapsed since 1970.
echo $RANDOM % 10 + 1 | bc
You can also use /dev/urandom:
grep -m1 -ao '[0-9]' /dev/urandom | sed s/0/10/ | head -n1
To generate in the range: {0,..,9}
r=$(( $RANDOM % 10 )); echo $r
To generate in the range: {40,..,49}
r=$(( $RANDOM % 10 + 40 )); echo $r
Here is example of pseudo-random generator when neither $RANDOM nor /dev/urandom is available
echo $(date +%S) | grep -o .$ | sed s/0/10/