Round a divided number in Bash - linux

How would I round the result from two divided numbers, e.g.
3/2
As when I do
testOne=$((3/2))
$testOne contains "1" when it should have rounded up to "2" as the answer from 3/2=1.5

To do rounding up in truncating arithmetic, simply add (denom-1) to the numerator.
Example, rounding down:
N/2
M/5
K/16
Example, rounding up:
(N+1)/2
(M+4)/5
(K+15)/16
To do round-to-nearest, add (denom/2) to the numerator (halves will round up):
(N+1)/2
(M+2)/5
(K+8)/16

Good Solution is to get Nearest Round Number is
var=2.5
echo $var | awk '{print int($1+0.5)}'
Logic is simple if the var decimal value is less then .5 then closest value taken is integer value. Well if decimal value is more than .5 then next integer value gets added and since awk then takes only integer part. Issue solved

bash will not give you correct result of 3/2 since it doesn't do floating pt maths. you can use tools like awk
$ awk 'BEGIN { rounded = sprintf("%.0f", 3/2); print rounded }'
2
or bc
$ printf "%.0f" $(echo "scale=2;3/2" | bc)
2

If you have integer division of positive numbers which rounds toward zero, then you can add one less than the divisor to the dividend to make it round up.
That is to say, replace X / Y with (X + Y - 1) / Y.
Proof:
Case 1: X = k * Y (X is integer multiple of Y): In this case, we have (k * Y + Y - 1) / Y, which splits into (k * Y) / Y + (Y - 1) / Y. The (Y - 1)/Y part rounds to zero, and we are left with a quotient of k. This is exactly what we want: when the inputs are divisible, we want the adjusted calculation to still produce the correct exact quotient.
Case 2: X = k * Y + m where 0 < m < Y (X is not a multiple of Y). In this case we have a numerator of k * Y + m + Y - 1, or k * Y + Y + m - 1, and we can write the division out as (k * Y)/Y + Y/Y + (m - 1)/Y. Since 0 < m < Y, 0 <= m - 1 < Y - 1, and so the last term (m - 1)/Y goes to zero. We are left with (k * Y)/Y + Y/Y which work out to k + 1. This shows that the behavior rounds up. If we have an X which is a k multiple of Y, if we add just 1 to it, the division rounds up to k + 1.
But this rounding is extremely opposite; all inexact divisions go away from zero. How about something in between?
That can be achieved by "priming" the numerator with Y/2. Instead of X/Y, calculate (X+Y/2)/Y. Instead of proof, let's go empirical on this one:
$ round()
> {
> echo $((($1 + $2/2) / $2))
> }
$ round 4 10
0
$ round 5 10
1
$ round 6 10
1
$ round 9 10
1
$ round 10 10
1
$ round 14 10
1
$ round 15 10
2
Whenever the divisor is an even, positive number, if the numerator is congruent to half that number, it rounds up, and rounds down if it is one less than that.
For instance, round 6 12 goes to 1, as do all values which are equal to 6, modulo 12, like 18 (which goes to 2) and so on. round 5 12 goes down to 0.
For odd numbers, the behavior is correct. None of the exact rational numbers are midway between two consecutive multiples. For instance, with a denominator of 11 we have 5/11 < 5.5/11 (exact middle) < 6/11; and round 5 11 rounds down, whereas round 6 11 rounds up.

Given a floating point value, we can round it trivially with printf:
# round $1 to $2 decimal places
round() {
printf "%.${2:-0}f" "$1"
}
Then,
# do some math, bc style
math() {
echo "$*" | bc -l
}
$ echo "Pi, to five decimal places, is $(round $(math "4*a(1)") 5)"
Pi, to five decimal places, is 3.14159
Or, to use the original request:
$ echo "3/2, rounded to the nearest integer, is $(round $(math "3/2") 0)"
3/2, rounded to the nearest integer, is 2

To round up you can use modulus.
The second part of the equation will add to True if there's a remainder. (True = 1; False = 0)
ex: 3/2
answer=$(((3 / 2) + (3 % 2 > 0)))
echo $answer
2
ex: 100 / 2
answer=$(((100 / 2) + (100 % 2 > 0)))
echo $answer
50
ex: 100 / 3
answer=$(((100 / 3) + (100 % 3 > 0)))
echo $answer
34

If the decimal separator is comma (eg : LC_NUMERIC=fr_FR.UTF-8, see here):
$ printf "%.0f" $(echo "scale=2;3/2" | bc)
bash: printf: 1.50: nombre non valable
0
Substitution is needed for ghostdog74 solution :
$ printf "%.0f" $(echo "scale=2;3/2" | bc | sed 's/[.]/,/')
2
or
$ printf "%.0f" $(echo "scale=2;3/2" | bc | tr '.' ',')
2

Another solution is to do the division within a python command. For example:
$ numerator=90
$ denominator=7
$ python -c "print (round(${numerator}.0 / ${denominator}.0))"
Seems less archaic to me than using awk.

I think this should be enough.
$ echo "3/2" | bc

Following worked for me.
#!/bin/bash
function float() {
bc << EOF
num = $1;
base = num / 1;
if (((num - base) * 10) > 1 )
base += 1;
print base;
EOF
echo ""
}
float 3.2

Related

AWK: merge two files based on the overlapping range given in the files

Let me explain my problem using a dummy example.
This is file A -
1 10 20 aa
2 30 40 bb
3 60 70 cc
. .. .. ..
and This is file B -
10 15 xx yy mm
21 29 mm nn ss
11 18 rr tt yy
69 90 qq ww ee
.. .. .. .. ..
I am trying to merge these files A and B such that there exist some overlapping between A's row and B's row.
Overlapping between A's row and B's row, in my case:
there is something common between range starting from $2 to $3 for A's row and range starting from $1 to $2 for B's row. in above example, there is overlapping between range(10,20) and range(10,15).
Here range(10,20) = [10,11,12,13,14,15,16,17,18,19] and
range(10,15) = [10,11,12,13,14]
So the expected output is -
1 10 20 aa 10 15 xx
1 10 20 aa 11 18 rr
3 60 70 cc 69 90 qq
I tried this way (using and awk):
for peak in State.peaks:
i = peak[-1]
peak = peak[:-1]
a = peak[1]
b = peak[2]
d = State.delta
c = ''' awk '{id=%d;delta=%d;a=%d;b=%d;x=%s;y=%s;if((x<=a&&y>a)||(x<=b&&y>b) || (x>a&&y<=b)) print id" "$7" "$3-$2} ' %s > %s ''' % (i, d, a, b, "$2-d", "$3+d", State.fourD, "file"+str(name))
os.system(c)
Wanted to remove python part completely as it is taking much time.
awk to the rescue!
$ awk 'function intersect(x1,y1,x2,y2)
{return (x1>=x2 && x1<y2) || (x2>=x1 && x2<y1)}
NR==FNR{lower[$0]=$2; upper[$0]=$3; next}
{for(k in lower)
if(intersect(lower[k],upper[k],$1,$2))
print k,$1,$2,$3}' file1 file2
Note that
(x1>=x2 && x1<y2) || (x2>=x1 && x2<y1)
= [x1>=x2 || (x2>=x1 && x2<y1)] && [x1<y2 || (x2>=x1 && x2<y1)]
= [(x1>=x2 || x2>=x1) && (x1>=x2 || x2<y1) && [// symmetric 1~2]
= [True && x2 < max(x1,y1)] && [// symmetric 1~2]
= x2<y1 && y2<x1
which is equivalent to #Jonathan Leffler's condition, which is more compact and more efficient, even though not trivial at first sight.
This Awk script does the job:
NR == FNR { record[NR] = $0; lo[NR] = $2; hi[NR] = $3; nrecs = NR; next }
NR != FNR { # Overlap: lo[A] < hi[B] && lo[B] < hi[A]
for (i = 1; i <= nrecs; i++)
{
if (lo[i] < $2 && $1 < hi[i])
print record[i], $1, $2, $3
}
}
I saved it as range-merge-53.awk (53 is simply a random double-digit prime). I created file.A and file.B from your sample data, and ran:
$ awk -f range-merge-53.awk file.A file.B
1 10 20 aa 10 15 xx
1 10 20 aa 11 18 rr
3 60 70 cc 69 90 qq
$
The key is the 'overlap' condition, which must exclude the high value of each range — often denoted [lo..hi) for an open-closed range.
It would be possible to omit either the next or the NR != FNR condition (but not both) and the code would work as well.
See also Determine whether two date ranges overlap — the logic of ranges applies to dates and integers and floating point, etc.

Stata Replacing Part of String

I have 10 digit long string "0000000000" called my_var. I have two variables highclass (between 0 and 10) and lowclass (between 0 and 10).
I need to convert the digits between highclass and lowclass to 1.
For example, if a row has highclass =5 and lowclass =1, then my_var should become 1111100000.
I am not sure if the substring command will help me since I need to reference a variable.
As I understand it, lowclass is the position of the first 1 and highclass is the position of the last 1.
No loops are needed. In fact, a single statement would do it in Stata (which is the language the question is about).
Two ways to do it:
Old style (particularly pertinent to Stata 12 and below)
Here I have split the single statement into several, because I suspect it is clearer that way. Note that substr() (not substring()) is a function, not a command.
clear
input str10 my_var lowclass highclass
"0000000000" 1 5
"0000000000" 2 4
"0000000000" 3 3
"0000000000" 1 10
"0000000000" 7 10
end
local zeros "0000000000"
local ones "1111111111"
replace my_var = substr("`zeros'", 1, lowclass - 1)
replace my_var = my_var + substr("`ones'", 1, highclass - lowclass + 1)
replace my_var = my_var + substr("`zeros'", 1, 10 - highclass)
list
+----------------------------------+
| my_var lowclass highcl~s |
|----------------------------------|
1. | 1111100000 1 5 |
2. | 0111000000 2 4 |
3. | 0010000000 3 3 |
4. | 1111111111 1 10 |
5. | 0000001111 7 10 |
+----------------------------------+
New style (Stata 13 up)
Mata and Stata 13 up allow string multiplication, (e.g. 10 * "1") so this works:
replace my_var = (lowclass - 1) * "0" + (highclass - lowclass + 1) * "1" + (10 - highclass) * "0"
Note that e.g. -1 * "0" is perfectly legal but evaluates as missing (empty string).

Calculate average of 1kb windows

My files looks like the following:
18 1600014 + CAA 0 3
18 1600017 - CTT 0 1
18 1600019 - CTC 0 1
18 1600020 + CAT 0 3
18 1600031 - CAA 0 1
18 1600035 - CAT 0 1
...
I am trying to calculate the average of column 6 in windows that cover 1000 range of column 2. So from 1600001-1601000, 1601001-1602000, etc. My values go from 1600000-1700000. Is there any way to do this is one step? My initial thought was to use grep to sort these values, but that would require many different commands. I am aware you can calculate the average with awk but can you reiterate over each window?
Desire output would be something like this:
1600001-1601000 3.215
1601001-1602000 3.141
1602001-1603000 3.542
You can use GNU awk to gather the counts and sums, if I understand your problem correct, you might need something like this:
BEGIN { mod = 1000
PROCINFO["sorted_in"] = "#ind_num_asc"
}
{
k= ($2 - ( $2 % mod ) ) / mod
sum[ k ]+= $6
cnt[ k ]++
}
END {
for( k in sum ) printf( "%d-%d\t%6.3f\n", k*mod +1, (k+1)*mod, sum[k] / cnt [k])
}

how to random lines in txt with bash

I have a txt file with some lines such as:
a
b
c
f
e
f
1
2
3
4
5
6
now I want to random lines and print it to another txt file for example:
f
6
e
1
and so on...
could any body help me?
I am new in bash scripting
You could use shuf (a part of GNU coreutils).
shuf inputfile > outfile
For example:
$ seq 10 | shuf
7
5
8
3
9
4
10
1
6
2
There is an option for that
sort -R /your/file.txt
Expanation
-R, --random-sort
sort by random hash of keys
Iterate over the file, outputting each line with a certain probability (in this example, with roughly a 10% chance for each line:
while read line; do
if (( RANDOM % 10 == 0 )); then
echo "$line"
fi
done < file.txt
(I say "roughly", because the value of RANDOM ranges between 0 and 32767. As such, there are slightly more values that will produce a remainder of 0-7 than there are that will produce a remainder of 8 or 9 when divided by 10. Other probabilities are have similar problems; you can fine-tune the expression to be more precise, but I leave that as an exercise to the reader.)
For less fortunates systems without GNU utils like BSD/OSX you can use this code:
for ((i=0; i<10; i++)); do
n=$((RANDOM%10))
sed $n'q;d' file
done

Modular Arithmetic in Haskell

How would I go about making a function so that x has a range of values from x=0 to x=19 and if the x value exceeds 19 or is below zero how can I get it to wrap around
From:
x=20, x=21, x=22 and x=(-1), x=(-2), x=(-3)
To:
x=0, x=1, x=2 and x=19, x=18, x=17 respectively?
I've heard of modular arithmetic which is apparently the way I should deal with it.
Usually you would use the built-in functions mod and rem, but I assume they are off-limits for homework. So you can write your own function, e.g.
mod20 x | x < 0 = ...
| x > 19 = ...
| otherwise = x
There are different things you can try to fill in the ...s. One of the easiest is repeated addition or subtraction, but I don't want to spoil all the fun.
Once you have this function, you can "rescale" the values after every "normal" arithmetic operation, e.g. mod20 (12 + 17).
Try using the mod function:
(-5) `mod` 20 ==> 15
5 `mod` 20 ==> 5
20 `mod` 20 ==> 0
25 `mod` 20 ==> 5
See also wikipedia on the topic.
Use
x `mod` 20
(This is a filler to make the answer 30 characters.)

Resources