Here is an answer without modulo 2 and pure bash, which works with negative percentage:
echo "$(( 200*item/total - 100*item/total ))"
We could define a generic integer division that rounds to the nearest integer and then apply it.
function rdiv {
echo $(( 2 * "$1"/"$2" - "$1"/"$2" ))
}
rdiv "$((100 * $item))" "$total"
In general, to compute the nearest integer using float to int conversion, one can use, say in Java : n = (int) (2 * x) - (int) x;
Explanation (based on binary expansion):
Let fbf(x)
be the first bit of the fractional part of x
, keeping the sign of x
. Let int(x)
be the integer part, which is x
truncated toward 0, again keeping the sign of x
. Rounding to the nearest integer is
round(x) = fbf(x) + int(x).
For example, if x = 100*-30/70 = -42.857
, then fbf(x) = -1
and int(x) = -42
.
We can now understand the second answer of Michael Back, which is based on modulo 2, because:
fbf(x) = int(2*x) % 2
We can understand the answer here, because:
fbf(x) = int(2*x) - 2*(int(x))
An easy way to look at this formula is to see a multiplication by 2
as shifting the binary representation to the left. When we first shift x
, then truncate, we keep the fbf(x)
bit that we lose if we first truncate, then shift.
The key point is that, in accordance with Posix and the C standard, a shell does a "rounding" toward 0, but we want a rounding toward the closest integer. We just need to find a trick to do that and there is no need for modulo 2.