Interi
Generalmente non vogliamo usare i doppi perché non vogliamo usare le operazioni in virgola mobile, gli errori di arrotondamento ecc. Non sono necessari.
Per questo è una buona idea ricordare come eseguire la divisione del soffitto: ceil(x / y)
in doppio può essere scritto come(x + y - 1) / y
(evitando numeri negativi, ma attenzione all'overflow).
Leggibile
Se vai per la leggibilità puoi ovviamente anche programmarlo in questo modo (esempio in Java, per C potresti usare le macro, ovviamente):
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
Imbottito
Sappiamo che abbiamo bisogno di blocchi di 4 caratteri alla volta per ogni 3 byte (o meno). Quindi la formula diventa (per x = n e y = 3):
blocks = (bytes + 3 - 1) / 3
chars = blocks * 4
o combinato:
chars = ((bytes + 3 - 1) / 3) * 4
il tuo compilatore ottimizzerà il 3 - 1
, quindi lascialo così per mantenere la leggibilità.
non imbottita
Meno comune è la variante non imbottita, per questo ricordiamo che ognuno ha bisogno di un carattere per ogni 6 bit, arrotondato per eccesso:
bits = bytes * 8
chars = (bits + 6 - 1) / 6
o combinato:
chars = (bytes * 8 + 6 - 1) / 6
possiamo comunque dividere ancora per due (se vogliamo):
chars = (bytes * 4 + 3 - 1) / 3
Illeggibile
Nel caso in cui non ti fidi del tuo compilatore per fare le ottimizzazioni finali per te (o se vuoi confondere i tuoi colleghi):
Imbottito
((n + 2) / 3) << 2
non imbottita
((n << 2) | 2) / 3
Quindi ci sono due modi logici di calcolo e non abbiamo bisogno di rami, bit-op o modulo-op - a meno che non lo vogliamo davvero.
Appunti:
- Ovviamente potrebbe essere necessario aggiungere 1 ai calcoli per includere un byte di terminazione nullo.
- Per Mime potrebbe essere necessario occuparsi dei possibili caratteri di fine riga e simili (cercare altre risposte per questo).