73

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

sashoalm
  • 75,001
  • 122
  • 434
  • 781
Mint
  • 14,388
  • 30
  • 76
  • 108
  • Essentially a DUP of SO 2394988 (http://stackoverflow.com/questions/2394988) - same poster. – Jonathan Leffler Mar 07 '10 at 07:19
  • Granted it's very similar, but I wouldn't call it a DUP, but feel free to close it now, since I have gotten my answer now anyway, thanks ghostdog! – Mint Mar 07 '10 at 08:41
  • 6
    Agreed! The two questions are not the same. One is asking for ceiling. This one asks for rounding which may be rounding up or down. – shparekh Sep 16 '14 at 18:26

11 Answers11

110

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
Regexident
  • 29,441
  • 10
  • 93
  • 100
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • 9
    Can you explain this a bit more? Whats denom mean for one? And I don't really get what all these brackets and letters are doing…? I feel I should know since there have been no other answers and 5+ ups – Mint Mar 07 '10 at 07:48
  • 22
    @Mint: He is showing a generalized answer using algebraic notation. Using your Bash example, it would look like this: `testOne=$(( (3 + (2 - 1) / 2))`. Even more generally, but in Bash syntax, it would be something like `answer=$(( ($numerator + ($denominator - 1) / $denomonator))`. You can also do it this way which eliminates all the dollar signs and allows more freedom with spaces (such as around the equal sign): `((answer = (numerator + (denominator - 1) / denomonator))` – Dennis Williamson Mar 07 '10 at 14:25
  • Yeah, I made some typos on those parentheses. – Dennis Williamson Mar 08 '10 at 05:58
  • @tommy.carstensen: You are correct. There's no indication here that the problem involves negative numbers (script questions usually do not). Negative numbers can be handled a similar way, but the formula gets more complicated quickly. – Ben Voigt Jan 24 '14 at 16:14
  • 6
    Incorrect `testOne=$(( (3 + (2 - 1) / 2))` correct: `testOne=$(( (3 + (2 - 1)) / 2))` – Pro Backup Mar 05 '17 at 17:36
58

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

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Ashish
  • 1,856
  • 18
  • 30
  • It was very useful while I was converting memory usage from KB to MB as I don't care much on decimal part – ashah Apr 04 '17 at 10:05
31

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
ghostdog74
  • 327,991
  • 56
  • 259
  • 343
  • 1
    awk 'BEGIN { rounded = sprintf("%.0f", 1/2); print rounded }' returns 0 and not 1. – tommy.carstensen Jan 24 '14 at 11:49
  • 3
    You should note that this does unbiased rounding. – Zombo Feb 11 '14 at 23:51
  • I like this one, since it's more readable (mathematical workarounds are nice but not readable), and I don't need precision over the 0.5 rounding. Please note that `awk 'BEGIN { rounded = sprintf("%.0f", 1.000001/2); print rounded }'` returns 1 – Kar.ma Apr 06 '17 at 16:52
  • Unbiased rounding means `$ echo 4.5 |awk '{printf "%.0f",$0}'` gives 4 while `$ echo 5.5 |awk '{printf "%.0f",$0}'` gives 6 – rounds .5 to nearest *even* integer – unhammer Nov 16 '18 at 11:31
14

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.

Kaz
  • 55,781
  • 9
  • 100
  • 149
  • This is a great solution, and I like it being bundled as a function. For clarification, the function `round x y` takes `x` divided by `y` and rounds to the nearest integer. – Ro Yo Mi Jul 30 '19 at 13:34
6

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
sk8asd123
  • 1,665
  • 16
  • 14
6

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
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
tyggr
  • 61
  • 1
  • 1
  • 1
    `printf "%.0f" "0.5"` prints `0` instead of the expected `1`, while `printf "%.0f" "0.6"` prints `1` as expected. – Alexej Magura Nov 11 '16 at 15:30
  • IMHO `printf "%.2f" "$1"` is wrong: `printf "%.0f" "2.6"`: `bash: printf: 2.6: invalid number`. – pevik Sep 18 '19 at 08:56
  • 1
    Made a typo. Should be `printf "%.${2:-0}f" "$1"`. I cannot change 1 character :-( – Marco Jan 22 '20 at 13:34
  • `printf` parses input number according to the locale, so, if the format of numbers in your locale does not match the English syntax (e.g. if the decimal separator is a comma), then `printf "%f" 0.5` yields `invalid number`. To fix this, reset the locale locally, like so: `LC_ALL=C printf ...` – Maëlan Jan 05 '23 at 13:56
2

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
Community
  • 1
  • 1
Q-D
  • 21
  • 1
1

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.

Sean Staats
  • 297
  • 4
  • 10
  • addendum: when rounding down you can also use floor division: print ${numerator} // ${denominator} – Jarno Sep 29 '16 at 20:58
  • 2
    Why do not call Java from bash? According to creators Java is very fast and have high performance of arithmetic operations. It is a joke certainly, but this joke is very sad, because your example is just as ridiculous as Java's arithmetic in bash. – Dennis V Jun 21 '20 at 19:01
1

I think this should be enough.

$ echo "3/2" | bc 
guest
  • 11
  • 2
1

You could use the function r(x, p)

By the manpage of the bc command:

r(x, p)

       : Returns x rounded to p decimal places

Here is an Ex.

#!/bin/bash
read expression
echo "r($expression,3)" | bc -l

The result of executing the script on 5+50*3/20 + (19*2)/7 is 17.929

Note: r(x, p) is implemented in the Extended Library and in order to use it you should either use the -l or --mathlib flags:

All of the functions below, including the functions in the extended
   math library (see the Extended Library subsection below), are available
   when the -l or --mathlib command-line flags are given, except that the
   extended math library is not available when the -s option, the -w
   option, or equivalents are given.
Ayoub Falah
  • 484
  • 3
  • 19
0

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
xs2rashid
  • 953
  • 12
  • 16