Dato un file (binario o testuale), qual è il modo più veloce o elegante in C++ per contare gli uni e gli zeri nella rappresentazione binaria di quel file?Come faccio a contare gli zeri e quelli in un file?
risposta
mi sento di raccomandare di utilizzare i risultati di matrice:
unsigned char cheating[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3,
4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2,
3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4,
5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2,
3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4,
5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5,
6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3,
4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3,
4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6,
7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4,
5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5,
6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 };
Dopo aver letto il file come unsigned char serie si può semplicemente somma:
for (int i = 0; i < arraysize; i++) {
sum0+=8-cheating[unsignedbytearray[i]];
sum1+=cheating[unsignedbytearray[i]];
}
E 'molto difficile da scrivere codice , che sarebbe più veloce o più elegante: P
+1: per fornire l'array (potrebbe essere necessario aggiungere una nota su come è stato generato). Dato che 'byte' non è un tipo standard, potresti voler usare' unsinged char' e 'const'-ify it. E. non è affatto un inganno :-), l'ho visto in molte implementazioni di 'std :: bitset' e l'ho usato nell'implementazione di' bitset' che ho scritto. Guardami rispondere – Arun
Non preoccupatevi di tracciare sia sum0 che sum1, basta calcolare sum0 = 8 * arraysize - sum1 –
È possibile generare questo, interrogando ** DigitCount [0 ... 255,2,1] ** in wolframalfa: http: // www .wolframalpha.com/input /? i = DigitCount [0 ... 255, + 2, + 1] – Margus
Vorrei leggere nel file uno unsigned int
alla volta e contare il numero di bit attivati in ciascuno fino a EOF. È possibile utilizzare l'algoritmo di calcolo sparse classico per contare il numero di 1
s in un valore unsigned int
.
int bitcount (unsigned int n)
{
int count = 0 ;
while (n) {
count++ ;
n &= (n - 1) ;
}
return count ;
}
solo fare il sopra per tutti letto in unsigned int
valori e mantenere un totale parziale.
Sulla maggior parte dei sistemi il tempo di esecuzione principale sarà i/o-bound. E come ottenere l'I/O più veloce dipende molto dal sistema. Quindi non c'è una sola risposta al "più veloce".
La maggior parte "elegante" dipende dagli occhi che vedono.
Quindi, in sintesi, nessuna delle due domande ha una risposta definitiva; suona come la pesca di soluzioni per un compito a casa. Sono i compiti?
No, non è compito. I miei amici e io, a metà scherzoso, consideriamo i file con meno di zero rispetto a quelli fisicamente meno pesanti e quindi preferibili, quindi ero curioso di sapere come procedere con il conteggio degli zeri e di quelli. –
"mezzo-scherzoso" ..? Significa che per metà credi che sia vero? – stib
@ stib: non deve essere metà scherzo, metà * vero *. Potrebbe essere un mezzo scherzo, una mezza frode ;-) –
Creare un array di caratteri di lunghezza 256. Flusso attraverso il file un byte alla volta incrementando la posizione dell'array di ogni byte. Codice hard il numero di 1s in ciascuno dei 256 byte in un altro array. Moltiplica i 2 array e somma.
Non sono sicuro dell'eleganza e richiede sicuramente più memoria, ma potrebbe essere più veloce dell'algoritmo di linuxuser27.
overflow 'char'? –
ya, buon punto, questo è un problema ... Margus sopra risolve quello. – aepryus
Ogni volta che voglio sapere il miglior trick manipolazione po 'per un particolare compito, mi metto qui: http://graphics.stanford.edu/~seander/bithacks.html
In "Counting bit impostati, in parallelo" elencano un metodo 12 operazione per contare i bit impostati in un Numero intero a 32 bit. Mostrano anche metodi per numeri interi maggiori di 32 bit.
Link interessante, grazie per aver postato questo. –
Proverei ad usare std::bitset
, ha una buona implementazione di il metodo count()
(count interface) mantenendo una matrice pre-calcolata di lunghezza 256 per il conteggio di tutti i possibili byte . Per zeri conteggio,
std::bitset<N> bs;
size_t zero_count = bs.size() - bs.count();
avrei inizializzare file_zero_count = 0
e aprire il file. Quindi, in ogni iterazione di un ciclo, leggevo i bit N
in un set di bit e aggiungo lo zero_count
di quei bit N
allo file_zero_count
. Quindi leggi i successivi N
bit e così via ...
La scelta cruciale è il valore di N
. La mia prima scelta sarebbe tale che i bit N
si inseriscano in una pagina di memoria, ad es. N = 4096
.
Un modo facile e veloce consiste nel creare una tabella di ricerca che indichi quanti caratteri 1 hanno, ad es. 'a' con ASCII 97 ha 3. È possibile memorizzare una tale tabella di ricerca in una matrice a lunghezza fissa per l'accesso a tempo costante. Caricare il file pagina per pagina nella memoria per ridurre al minimo il numero di I/O e contare per ogni carattere in sequenza.
Se si dispone di ulteriori informazioni sul tipo di dati che si stanno elaborando, è possibile creare soluzioni più interessanti. Ad esempio, se si sa che il file contiene dati testuali in linguaggio naturale, è possibile creare tabelle di ricerca per termini ricorrenti come "il", "di" e "e" per accelerare i calcoli di conteggio. Tale tabella di ricerca può essere memorizzata in modo efficiente nella tabella hash.
avrei letto nel file byte per byte e contare il numero di 1/0 in ogni byte:
Il motivo avrei scelto byte è che è facile mettere insieme un LOOKUPTABLE per il numero di 1 in un byte a mano. Nota: stavo contando il numero di quelli in un byte. Ma ho costruito la tabella all'indietro (quindi è in realtà un conteggio del numero di 0 (poiché è l'inverso degli 1)).
int countOne[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, // Top Line + 1 2^5 (16 set)
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, // Top Line + 1 2^6 (32 set)
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, // Top Line + 2 2^5 + 2^6 (16/32 set)
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, // Top Line + 1 2^7 (64 set)
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, // Top Line + 2 2^5 + 2^7 (16/64 set)
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, // Top Line + 2 2^6 + 2^7 (32/64 set)
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, // Top Line + 3 2^5 + ^6 + 2^7 (16/32/64 set)
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, // Top Line + 1 2^8 (128 set)
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, // Top Line + 2 2^5 + 2^8 (16/128 set)
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, // Top Line + 2 2^6 + 2^8 (32/128 set)
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, // Top Line + 3 2^5 + 2^6 + 2^8 (16/32/128 set)
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, // Top Line + 2 2^7 + 2^8 (64/128 set)
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, // Top Line + 3 2^5 + 2^7 + 2^8 (16/64/128 set)
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, // Top Line + 3 2^6 + 2^7 + 2^8 (32/64/128 set)
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8};
Ora tutto quello che dovete fare è utilizzare uno std :: for_each che iterater attraverso un flusso (senza spazi cadere.
counter = std::for_each(std::istreambuf_iterator<unsigned char>(file),
std::istreambuf_iterator<unsigned char>(),
couter);
Ora non vi resta che definire un tipo appropriato per il contatore e la il resto è storia
Controlla se il char è stato firmato, poiché finirai per indicizzare fuori dai limiti di countOne, a meno che non ricominci al char non firmato. –
Ecco un esempio completo (beh quasi c'è un esercizio per l'implementatore alla fine ...) Utilizza il conteggio di 12 istruzioni per i valori a 32 byte da http://graphics.stanford.edu/~seander/bithacks.html. Inoltre carica il file utilizzando mmap come quello è (spesso) più veloce di altri read read hods. Penso che l'unica cosa da fare per renderlo più veloce sarebbe dividere il conteggio su più thread. Ma sul mio sistema già processa file da 10 MB in meno di 0.03, il che mi sembra OK.
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <iostream>
#include <unistd.h>
int main()
{
int fd = open("junk.txt",O_RDWR);
struct stat info;
fstat(fd, &info);
void * page = mmap(0, info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
uint64_t bitcount = 0;
//Lets ignore alignment issues for now - I think mmap guarantees that they're OK.
uint32_t * v_ptr = static_cast<uint32_t*>(page);
for(unsigned int i=0; i<info.st_size/4; ++i)
{
uint32_t v = *v_ptr;
v = v - ((v >> 1) & 0x55555555); // reuse input as temporary
v = (v & 0x33333333) + ((v >> 2) & 0x33333333); // temp
bitcount += ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count
++v_ptr;
}
//Need to adjust for the last 0-3 bytes... Exercise for the reader
munmap(page, info.st_size);
std::cout<<"Total of "<<bitcount<<" set bits"<<std::endl;
}
- 1. In Python, come faccio a contare gli zeri finali in una stringa o in un intero?
- 2. Contare gli zeri iniziali in una Int32
- 3. In VHDL ..... come contare gli zeri iniziali del vettore?
- 4. Flipping zeri e quelli in unidimensionale matrice NumPy
- 5. Come faccio a contare le parole giapponesi in Go-lang
- 6. Come contare gli elementi in TinyXml?
- 7. Come contare tutti gli elementi in un dizionario annidato?
- 8. come faccio a mettere in pausa e riprendere un timer?
- 9. Come faccio a sapere quando un'interfaccia viene implementata direttamente in un tipo ignorando quelli ereditati?
- 10. Come contare quanti ascoltatori sono collegati a un evento?
- 11. Come contare gli oggetti JSON
- 12. C# - Come faccio a leggere e scrivere un file binario?
- 13. VB - Come faccio a leggere e scrivere un file binario?
- 14. Converti in binario e mantiene gli zeri iniziali in Python
- 15. Java aggiunge gli zeri iniziali a un numero
- 16. Come aggiungere gli zeri con riempimento a sinistra a un numero in Java?
- 17. Confronto tra un lungo std_logic_vector e gli zeri
- 18. Come faccio a uscire dalle e commerciali in file batch?
- 19. django annotare e contare: come filtrare quelli da includere nel conteggio
- 20. NSString rimuovendo gli zeri iniziali?
- 21. Sostituire gli zeri in un array intero NumPy con nan
- 22. int.Parse() con gli zeri iniziali
- 23. Come faccio a contare il numero di parole in un testo (stringa)?
- 24. Come contare le righe in un file sul comando hdfs?
- 25. Aggiungere gli zeri a un float dopo il punto decimale in Python
- 26. JQuery - Come faccio a contare il numero di elementi selezionati da un selettore?
- 27. Come faccio a tessere un progetto a più file?
- 28. Come faccio a selezionare tutti gli input tranne in un ID specifico?
- 29. Come faccio a collegare un file .sks a un file .swift in SpriteKit
- 30. Come faccio a Log4j correttamente, chiudendo tutti gli Appenders e, quindi, i file
Mostraci cosa hai provato. – Zano
In media il numero di 1 deve essere uguale al numero di 0. Quindi se prendi la dimensione del file in byte allora moltiplica per 8 ottieni la somma di tutti gli zeri più la somma di tutti quelli. Il 50% sarà l'uno il 50% sarà zero –
Martin, che non dà un conteggio, che dà solo una stima, e anche la stima sarà molto bassa a meno che il contenuto del file non sia casuale (la maggior parte dei contenuti dei file non lo sono) –