How would I do something like:
ceiling(N/500)
N representing a number.
But in a linux Bash script
How would I do something like:
ceiling(N/500)
N representing a number.
But in a linux Bash script
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 (( ... )).)
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}"
perl -w -e 'use POSIX; print ceil($ARGV[0]/$ARGV[1]), qq{\n}' $N 500 is fine too, etc. TMTOWTDI. The important bit is using a standards-based ceil implementation.
– Josh McFadden
Mar 07 '10 at 04:11
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
}
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
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
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
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
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}
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
This is a simple solution using Awk:
If you want the ceil of ($a/$b) use
echo "$a $b" | awk '{print int( ($1/$2) + 1 )}'
and the floor use
echo "$a $b" | awk '{print int($1/$2)}'
Note that I just echo the dividend '$a' as the first field of the line to awk and the divisor '$b' as the second.
Some more concise Awk logic
awk '
function ceil(ip) {
print ip%1 ? int(ip)+1 : ip
}
BEGIN {
ceil(1000/500)
ceil(1001/500)
}
'
Result
2 3
Some more concise Awk logic
awk '
function ceil(ip) {
print ip%1 ? int(ip)+1 : ip
}
BEGIN {
ceil(1000/500)
ceil(1001/500)
}
'
Result
2 3
This function wont't add 1, if the division returns a non-floating number.
function ceiling {
DIVIDEND=${1}
DIVISOR=${2}
if [ $(( DIVIDEND % DIVISOR )) -gt 0 ]; then
RESULT=$(( ( ( $DIVIDEND - ( $DIVIDEND % $DIVISOR ) ) / $DIVISOR ) + 1 ))
else
RESULT=$(( $DIVIDEND / $DIVISOR ))
fi
echo $RESULT
}
Use it like this:
echo $( ceiling 100 33 )
> 4
Without specifying any function, we can use the following awk script:
echo x y | awk '{ r=$1 % $2; q=$1/y; if (r != 0) q=int(q+1); print q}'
Not sure this one get any logical error or not. Please correct.
If you are already familiar with the Python library, then rather than learn bc, you might want to define this bash function:
pc () { pyexpr="from math import *; print($@)"; python -c "$pyexpr"; }
Then:
pc "ceil(3/4)"
1
but also any valid python expression works:
pc pi / 4
0.7853981633974483
pc "'\n'.join(['Pythagoras said that %3.2f^2 + %3.2f^2 is always %3.2f'
% (sin(ai), cos(ai), sin(ai)**2 + cos(ai)**2)
for ai in [pi / 4 * k for k in range(8)]])"
Pythagoras said that 0.00^2 + 1.00^2 is always 1.00
Pythagoras said that 0.71^2 + 0.71^2 is always 1.00
Pythagoras said that 1.00^2 + 0.00^2 is always 1.00
Pythagoras said that 0.71^2 + -0.71^2 is always 1.00
Pythagoras said that 0.00^2 + -1.00^2 is always 1.00
Pythagoras said that -0.71^2 + -0.71^2 is always 1.00
Pythagoras said that -1.00^2 + -0.00^2 is always 1.00
Pythagoras said that -0.71^2 + 0.71^2 is always 1.00