Although you ask to do this in Bash, there's no native support for functions like square root or ceiling. It would be simpler to delegate to Perl:
perl -wmPOSIX -e "print POSIX::ceil((sqrt(1 + 8 * $n) - 1) / 2)"
Alternatively, you could use bc
to calculate the square root, and some Bash to calculate the ceiling.
Let's define a function that prints the result of the formula with sqrt
of bc
:
formula() {
local n=$1
bc -l <<< "(sqrt(1 + 8 * $n) - 1) / 2"
}
The -l
flag changes the scale
from the default 0 to 20.
This affects the scale in the display of floating point results.
For example, with the default zero, 10 / 3
would print just 3.
We need the floating point details in the next step to compute the ceiling.
ceil() {
local n=$1
local intpart=${n%%.*}
if [[ $n =~ \.00*$ ]]; then
echo $intpart
else
echo $((intpart + 1))
fi
}
The idea here is to extract the integer part,
and if the decimal part is all zeros, then we print simply the integer part,
otherwise the integer part + 1, as that is the ceiling.
And a final simple function that combines the above functions to get the result that you want:
compute() {
local n=$1
ceil $(formula $n)
}
And a checker function to test it:
check() {
local n num
for n; do
num=$(formula $n)
echo $n $num $(compute $n)
done
}
Let's try it:
check 1 2 3 4 7 11 12 16 17
It produces:
1 1.00000000000000000000 1
2 1.56155281280883027491 2
3 2.00000000000000000000 2
4 2.37228132326901432992 3
7 3.27491721763537484861 4
11 4.21699056602830190566 5
12 4.42442890089805236087 5
16 5.17890834580027361089 6
17 5.35234995535981255455 6