Целые
Обычно мы не хотим использовать удвоения, потому что мы не хотим использовать операции с плавающей запятой, ошибки округления и т. Д. Они просто не нужны.
Для этого полезно вспомнить, как выполнить деление потолка: ceil(x / y)
в парном разряде можно записать как(x + y - 1) / y
числах (избегая отрицательных чисел, но остерегаясь переполнения).
Удобочитаемый
Если вы стремитесь к читабельности, вы, конечно, можете также запрограммировать это так (например, на Java, для C вы, конечно, можете использовать макросы):
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));
}
}
встраиваемый
подбитый
Мы знаем, что нам нужно 4 блока символов одновременно на каждые 3 байта (или меньше). Итак, формула становится (для x = n и y = 3):
blocks = (bytes + 3 - 1) / 3
chars = blocks * 4
или в сочетании:
chars = ((bytes + 3 - 1) / 3) * 4
Ваш компилятор оптимизирует 3 - 1
, так что просто оставьте его таким, чтобы сохранить читабельность.
без ведущего
Менее распространенным является вариант без дополнения, для этого мы помним, что для каждого нам нужен символ для каждых 6 битов, округленный в большую сторону:
bits = bytes * 8
chars = (bits + 6 - 1) / 6
или в сочетании:
chars = (bytes * 8 + 6 - 1) / 6
однако мы можем все еще разделить на два (если мы хотим):
chars = (bytes * 4 + 3 - 1) / 3
нечитаемый
Если вы не доверяете вашему компилятору окончательную оптимизацию (или если вы хотите запутать своих коллег):
подбитый
((n + 2) / 3) << 2
без ведущего
((n << 2) | 2) / 3
Итак, у нас есть два логических способа вычисления, и нам не нужны никакие ветки, битовые операции или операции по модулю - если мы действительно этого не хотим.
Ноты:
- Очевидно, что вам может понадобиться добавить 1 к вычислениям, чтобы включить нулевой завершающий байт.
- Для Mime вам, возможно, придется позаботиться о возможных символах окончания строки и тому подобном (ищите другие ответы для этого).