[C++] Overload operatori bitwise per big_int
A differenza di [inline]>>[/inline] e [inline]<<[/inline], che ritengo utili in quanto consentono una rapida divisione e moltiplicazione per potenze di $2$, mi chiedevo se ha senso fornire l'overload degli operatori [inline]&[/inline], [inline]|[/inline], [inline]^[/inline] e [inline]~[/inline] per una classe sui big_int?! Secondo voi potrebbero tornare utili in qualche modo?
Relativamente allo scorrimento a destra e a sinistra, ecco le funzioni che ho scritto ("RR" nel nome delle funzioni indica che sia il vettore in input che quello in output contengono le cifre del big_int in base $2^32$ in ordine inverso):
Non ho ancora avuto modo di testarle per bene, quindi se riscontrate qualche bug o avete qualche consiglio per migliorarle, fatemi sapere.
Relativamente allo scorrimento a destra e a sinistra, ecco le funzioni che ho scritto ("RR" nel nome delle funzioni indica che sia il vettore in input che quello in output contengono le cifre del big_int in base $2^32$ in ordine inverso):
vector<uint32_t> right_shift_2to32_RR(const vector<uint32_t> &v1, const uint64_t n) { uint64_t q = n / 32; uint64_t r = n % 32; vector<uint32_t> v2 = q < v1.size() ? vector<uint32_t>(v1.begin() + q, v1.end()) : vector<uint32_t>(1, 0); if(v2.back() && r) { for(uint64_t i = 0; i < v2.size() - 1; ++i) { v2[i] = v2[i] >> r | v2[i + 1] << 32 - r; } if(!(v2.back() >>= r) && v2.size() != 1) { v2.pop_back(); } } return v2; } vector<uint32_t> left_shift_2to32_RR(const vector<uint32_t> &v1, const uint64_t n) { if(!v1.back()) { return {0}; } uint64_t q = n / 32; uint64_t r = n % 32; vector<uint32_t> v2(q + v1.size() + (r && v1.back() >> 32 - r), 0); for(uint64_t i_v1 = 0, i_v2 = q; i_v1 < v1.size(); v2[i_v2++] = v1[i_v1++]); if(r) { for(uint64_t i = v2.size() - 1; i > q; --i) { v2[i] = v2[i] << r | v2[i - 1] >> 32 - r; } v2[q] <<= r; } return v2; }
Non ho ancora avuto modo di testarle per bene, quindi se riscontrate qualche bug o avete qualche consiglio per migliorarle, fatemi sapere.
Risposte
Gli operatori che hai scritto lavorano tutti su singoli bit e quindi implementarli è abbastanza semplice. Tuttavia l'operatore BITWISE NOT ~ è problematico perché il risultato è una successione infinita di \(1\). Che significato vuoi dargli?
"apatriarca":
Gli operatori che hai scritto lavorano tutti su singoli bit e quindi implementarli è abbastanza semplice.
Gli operatori [inline]&[/inline], [inline]|[/inline], [inline]^[/inline] e [inline]~[/inline] non li ho ancora implementati, ma così, a naso, (al netto di alcune scelte implementative da fare) mi sembra un compito anche più semplice dell'implementazione di [inline]>>[/inline] e [inline]<<[/inline].
Il punto è se aggiungerli o no alla mia classe sui big_int... A livello pratico quale potrebbe essere l'utilità di [inline]&[/inline], [inline]|[/inline], [inline]^[/inline] o [inline]~[/inline] con i big_int?
Oppure li aggiungo e basta, fregandomene di se e come verranno eventualmente utilizzati?
"apatriarca":
Tuttavia l'operatore BITWISE NOT ~ è problematico perché il risultato è una successione infinita di 1. Che significato vuoi dargli?
Scusa, non capisco, in che senso il risultato sarebbe una successione infinita di 1? Il risultato dipende dal vettore in input, no?
Per esempio (ipotizzando per comodità di lavorare in base $2^5$) avremo che:
~{01001 10010 01101} = {10110 01101 10010}
Poi bisognerà fare anche alcune scelte implementative, per esempio si potrebbe optare per qualcosa del genere:
~{00000} = {11111}
~{11111 01001 11011} = {10110 00100}
~{11111 11111 11111 11111} = {00000}
Poi sull'utilità pratica di tutto ciò non saprei, per questo chiedevo!

Sinceramente non ho mai usato una libreria per grandi numeri interi, quindi non saprei dirti se hanno un'utilità. Probabilmente no.
Capisco, allora per il momento mi limito a fornire gli operatori [inline]<<[/inline] e [inline]>>[/inline], che un'utilità ce l'hanno di sicuro.