Complementando...
Com relação ao round, existem várias formas de arredondar em caso de "empate" (ou seja, quando a parte decimal é .5).
Entre as opções existentes, podemos listar as mais comuns:
- arredondar para o maior (ou seja,
2.5vira3e-2.5vira-2), também chamado de "em direção ao infinito positivo" (towards infinity) - arredondar para o menor (ou seja,
2.5vira2e-2.5vira-3), também chamado de "em direção ao infinito positivo negativo" (towards negative infinity) - arredondar para o valor mais próximo de zero (
2.5vira2e-2.5vira-2), também chamado de "towards zero" - arredondar para o valor mais distante de zero (
2.5vira3e-2.5vira-3), também chamado de "away from zero" - arredondar para o número par mais próximo (
2.5vira2e1.5também vira2) - essa é usada como o default em Python e C#- como curiosidade, esta regra também é conhecida como bankers rounding ou Banker's algorithm, tem mais detalhes sobre ela aqui.
- arredondar para o número ímpar mais próximo (
2.5vira3e1.5vira1)
A tabela abaixo tem um resumo disso:
| Valor | Towards +∞ | Towards -∞ | Par | Ímpar | Towards zero | Away from zero |
|---|---|---|---|---|---|---|
| 1.5 | 2 | 1 | 2 | 1 | 1 | 2 |
| 2.5 | 3 | 2 | 2 | 3 | 2 | 3 |
| -1.5 | -1 | -2 | -2 | -1 | -1 | -2 |
| -2.5 | -2 | -3 | -2 | -3 | -2 | -3 |
Muitas linguagens, inclusive, possuem formas de escolher qual opção queremos ao arredondar. Claro que nem todas as linguagens possuem todas as opções, e outras podem ter mais formas ainda. Python, por exemplo, possui a opção ROUND_05UP: se o último dígito depois de arredondar em direção ao zero for 0 ou 5, usa o critério away from zero , senão usa towards zero ("Round away from zero if last digit after rounding towards zero would have been 0 or 5; otherwise round towards zero").
Quanto ao fato de floor e ceiling darem resultados "inesperados" com números negativos, na verdade faz sentido se levarmos em conta a definição. floor arredonda "para baixo", ou seja, o resultado é um número inteiro menor ou igual ao valor original. Por isso que floor(-2.1) é -3 e não -2. De forma similar, ceiling(-2.9) é um número inteiro que é maior ou igual ao valor original, por isso é -2 e não -3.
Estas formas de arredondamento também costumam ser descritas como "towards negative infinity" (floor) e "towards positivy infinity" (ceil), ou seja, o número é arredondado em determinada direção na Reta Numérica:
floor(-1.2) ceil(-1.2) floor(1.2) ceil(1.2)
negative infinity <---- -2 --------- -1 ----- 0 ---- 1 -------- 2 ----> positive infinity
-1.2 1.2
No caso, floor arredonda em direção ao infinito negativo: a partir do número, começa-se a "caminhar" na direção do infinito negativo, e o resultado é o primeiro número inteiro que for encontrado neste caminho. ceil faz o mesmo em direção ao infinito positivo.
Vale notar que no caso de floor e ceil, o critério é usado sempre para qualquer número, ao contrário do round, que usa somente em caso de empate (pode usar algum dos já citados acima como o default, ou qualquer outro indicado via algum parâmetro). Ou seja, floor(2.9) e floor(2.5) resultam em 2, ceil(2.9) e ceil(2.5) resultam em 3, e round(2.9) resulta em 3. Mas round(2.5) pode ser 2 ou 3 dependendo do critério de desempate usado.
| Valor | floor | ceil | round |
|---|---|---|---|
| 2.1 | 2 | 3 | 2 |
| 2.5 | 2 | 3 | 2 ou 3 (depende do critério de desempate) |
| 2.9 | 2 | 3 | 3 |
Por fim, já escrevi um post bem detalhado sobre isso (do qual retirei/adaptei os trechos acima), serve como um complemento :-)