Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get ceiling integer from number in linux (BASH)

How would I do something like:

ceiling(N/500)

N representing a number.

But in a linux Bash script

like image 214
Mint Avatar asked Mar 07 '10 03:03

Mint


People also ask

What does [- Z $1 mean in bash?

$1 means an input argument and -z means non-defined or empty. You're testing whether an input argument to the script was defined when running the script. Follow this answer to receive notifications.

What is $_ in bash?

$_ (dollar underscore) is another special bash parameter and used to reference the absolute file name of the shell or bash script which is being executed as specified in the argument list. This bash parameter is also used to hold the name of mail file while checking emails.

What does %% mean in bash?

So as far as I can tell, %% doesn't have any special meaning in a bash function name. It would be just like using XX instead. This is despite the definition of a name in the manpage: name A word consisting only of alphanumeric characters and under- scores, and beginning with an alphabetic character or an under- score.


10 Answers

Why use external script languages? You get floor by default. To get ceil, do

$ divide=8; by=3; (( result=(divide+by-1)/by )); echo $result
3
$ divide=9; by=3; (( result=(divide+by-1)/by )); echo $result
3
$ divide=10; by=3; (( result=(divide+by-1)/by )); echo $result
4
$ divide=11; by=3; (( result=(divide+by-1)/by )); echo $result
4
$ divide=12; by=3; (( result=(divide+by-1)/by )); echo $result
4
$ divide=13; by=3; (( result=(divide+by-1)/by )); echo $result
5
....

To take negative numbers into account you can beef it up a bit. Probably cleaner ways out there but for starters

$ divide=-10; by=10; neg=; if [ $divide -lt 0 ]; then (( divide=-divide )); neg=1; fi; (( result=(divide+by-1)/by )); if [ $neg ]; then (( result=-result )); fi; echo $result
-1

$ divide=10; by=10; neg=; if [ $divide -lt 0 ]; then (( divide=-divide )); neg=1; fi; (( result=(divide+by-1)/by )); if [ $neg ]; then (( result=-result )); fi; echo $result
1

(Edited to switch let ... to (( ... )).)

like image 169
Kalle Avatar answered Oct 03 '22 22:10

Kalle


Call out to a scripting language with a ceil function. Given $NUMBER:

python -c "from math import ceil; print ceil($NUMBER/500.0)"

or

perl -w -e "use POSIX; print ceil($NUMBER/500.0), qq{\n}"
like image 29
Josh McFadden Avatar answered Oct 03 '22 22:10

Josh McFadden


Here's a solution using bc (which should be installed just about everywhere):

ceiling_divide() {
  ceiling_result=`echo "($1 + $2 - 1)/$2" | bc`
}

Here's another purely in bash:

# Call it with two numbers.
# It has no error checking.
# It places the result in a global since return() will sometimes truncate at 255.

# Short form from comments (thanks: Jonathan Leffler)
ceiling_divide() {
  ceiling_result=$((($1+$2-1)/$2))
}

# Long drawn out form.
ceiling_divide() {
  # Normal integer divide.
  ceiling_result=$(($1/$2))
  # If there is any remainder...
  if [ $(($1%$2)) -gt 0 ]; then
    # rount up to the next integer
    ceiling_result=$((ceiling_result + 1))
  fi
  # debugging
  # echo $ceiling_result
}
like image 41
Harvey Avatar answered Oct 03 '22 23:10

Harvey


Expanding a bit on Kalle's great answer, here's the algorithm nicely packed in a function:

ceildiv() {
    local num=$1
    local div=$2
    echo $(( (num + div - 1) / div ))
}

or as a one-liner:

ceildiv(){ echo $((($1+$2-1)/$2)); }

If you want to get fancy, you could use a more robust version validates input to check if they're numerical, also handles negative numbers:

ceildiv() {
    local num=${1:-0}
    local div=${2:-1}
    if ! ((div)); then
        return 1
    fi
    if ((num >= 0)); then
        echo $(( (num + div - 1) / div ))
    else
        echo $(( -(-num + div - 1) / div ))
    fi
}

This uses a "fake" ceil for negative numbers, to the highest absolute integer, ie, -10 / 3 = -4 and not -3 as it should, as -3 > -4. If you want a "true" ceil, use $(( num / div )) instead after the else

And then use it like:

$ ceildiv 10 3
4
$ ceildiv 501 500
2
$ ceildiv 0 3
0
$ ceildiv -10 1
-10
$ ceildiv -10 3
-4
like image 23
MestreLion Avatar answered Oct 03 '22 23:10

MestreLion


You can use jq if you have it installed. It's "sed for JSON", but I find it surprisingly handy for simple tasks like this too.

Examples:

$ echo 10.001 | jq '.|ceil'
11

$ jq -n '-10.001 | ceil'
-10
like image 29
Xiangming Hu Avatar answered Oct 03 '22 23:10

Xiangming Hu


You can use awk

#!/bin/bash
number="$1"
divisor="$2"
ceiling() {
  awk -vnumber="$number" -vdiv="$divisor" '
  function ceiling(x){return x%1 ? int(x)+1 : x}
  BEGIN{ print ceiling(number/div) }'
}
ceiling

output

$ ./shell.sh 1.234 500
1

Or if there's a choice, you can use a better shell that does floating point, eg Zsh

integer ceiling_result
ceiling_divide() {
  ceiling_result=$(($1/$2))
  echo $((ceiling_result+1))
}

ceiling_divide 1.234 500
like image 34
ghostdog74 Avatar answered Oct 03 '22 22:10

ghostdog74


Mathematically, the function of ceiling can be define with floor, ceiling(x) = -floor(-x). And, floor is the default when converting a positive float to integer.

if [ $N -gt 0 ]; then expr 1 - $(expr $(expr 1 - $N) / 500); else expr $N / 500; fi

Ref. https://en.wikipedia.org/wiki/Floor_and_ceiling_functions

like image 26
Frank R. Avatar answered Oct 03 '22 21:10

Frank R.


If you have a string representation of a decimal number, bash does support ceiling using printf function like this:

$ printf %.4f 0.12345
0.1235

But if you need to do some math using decimals, you can use bc -l that by default scales to 20 decimals, then use the result with printf to round it.

printf %.3f $(echo '(5+50*3/20 + (19*2)/7 )' | bc -l)
17.929
like image 37
ton Avatar answered Oct 03 '22 22:10

ton


Floor () {
  DIVIDEND=${1}
  DIVISOR=${2}
  RESULT=$(( ( ${DIVIDEND} - ( ${DIVIDEND} % ${DIVISOR}) )/${DIVISOR} ))
  echo ${RESULT}
}
R=$( Floor 8 3 )
echo ${R}

Ceiling () {
  DIVIDEND=${1}
  DIVISOR=${2}
  $(( ( ( ${DIVIDEND} - ( ${DIVIDEND} % ${DIVISOR}) )/${DIVISOR} ) + 1 ))
  echo ${RESULT}
}
R=$( Ceiling 8 3 )
echo ${R}
like image 39
bsaldivar Avatar answered Oct 03 '22 23:10

bsaldivar


Using the gorgeous 'printf' 1 will round up to the next integer

printf %.0f $float
or
printf %.0f `your calculation formula`
or
printf %.0f $(your calculation formula)

ref: how to remove decimal from a variable?

like image 37
splaisan Avatar answered Sep 23 '22 23:09

splaisan