Inteiros
Geralmente, não queremos usar duplos porque não queremos usar operações de ponto flutuante, erros de arredondamento etc. Eles simplesmente não são necessários.
Para isso, é uma boa idéia lembrar-se de como realizar a divisão do teto: o ceil(x / y)
dobro pode ser escrito como (x + y - 1) / y
(enquanto evita números negativos, mas cuidado com o excesso).
Legível
Se você busca legibilidade, é claro que também pode programá-lo desta forma (exemplo em Java, para C, você pode usar macro, é claro):
public static int ceilDiv(int x, int y) {
return (x + y - 1) / y;
}
public static int paddedBase64(int n) {
int blocks = ceilDiv(n, 3);
return blocks * 4;
}
public static int unpaddedBase64(int n) {
int bits = 8 * n;
return ceilDiv(bits, 6);
}
// test only
public static void main(String[] args) {
for (int n = 0; n < 21; n++) {
System.out.println("Base 64 padded: " + paddedBase64(n));
System.out.println("Base 64 unpadded: " + unpaddedBase64(n));
}
}
Inline
Acolchoado
Sabemos que precisamos de 4 blocos de caracteres por vez para cada 3 bytes (ou menos). Então a fórmula se torna (para x = ne y = 3):
blocks = (bytes + 3 - 1) / 3
chars = blocks * 4
ou combinado:
chars = ((bytes + 3 - 1) / 3) * 4
seu compilador otimizará o 3 - 1
, então deixe assim para manter a legibilidade.
Sem almofada
Menos comum é a variante não-acolchoada, para isso lembramos que cada um de nós precisa de um caractere para cada 6 bits, arredondado para cima:
bits = bytes * 8
chars = (bits + 6 - 1) / 6
ou combinado:
chars = (bytes * 8 + 6 - 1) / 6
no entanto, ainda podemos dividir por dois (se quisermos):
chars = (bytes * 4 + 3 - 1) / 3
Ilegível
Caso você não confie no seu compilador para fazer as otimizações finais para você (ou se você quiser confundir seus colegas):
Acolchoado
((n + 2) / 3) << 2
Sem almofada
((n << 2) | 2) / 3
Portanto, existem duas formas lógicas de cálculo e não precisamos de ramificações, operações de bits ou operações de módulos - a menos que realmente desejemos.
Notas:
- Obviamente, pode ser necessário adicionar 1 aos cálculos para incluir um byte de terminação nulo.
- Para o Mime, você pode precisar cuidar de possíveis caracteres de terminação de linha e outros (procure outras respostas para isso).