J'ai une gamme d'entiers, supposons qu'ils sont de type Quel est le moyen le plus efficace de convertir le tableau de la manière dont tous les espaces inutiles sont supprimés (c'est-à-dire que j'ai le premier entier à J'aimerais que cela soit général autant que possible, car Bien sûr que je sais que je peux simplement itérer la valeur de la valeur, je veux juste vous demander Stackoverflowers si vous pouvez penser à une manière plus intelligente. p>
EDIT: P>
Cette question ne consiste pas à comprimer le tableau pour prendre le moins d'espace possible. J'ai juste besoin de "couper" intz_t code>. Maintenant, je sais que seuls chaque premier
n code> de chaque entiers ont un sens (c'est-à-dire que je sais qu'ils sont limités par certaines limites). p>
A [0] code>, le second à
A [0] + n bits code> et ainsi de suite)? P>
N code> varierait de temps à autre, bien que je suppose que des optimisations intelligentes pourraient être spécifiques
n code> comme Pouvoirs de 2 ou de la STH. P>
n bits code> à partir de chaque entier et donné le tableau, je connais exactement
n code> de bits je peux couper en toute sécurité. p>
7 Réponses :
Je sais que cela pourrait sembler être la chose évidente de dire que je suis sûr qu'il y a une solution, mais pourquoi ne pas utiliser un type plus petit, comme et sur la note d'exercices académiques, Bit Twiddling Hacks est un bon Lire. p> uint8_t code> (max 255)? ou
uint16_t code> (max 65535) ?. Je suis sûr que vous pourriez être bit-manipuler sur un
intz_t code> à l'aide de valeurs définies et d'opérations et autres, mais, à part un exercice académique, pourquoi? P>
+1 pour une liaison cool. Eh bien, cela peut parfois être INT64_T avec, dire, 49 bits utiles. Donc, en utilisant de plus petit type dans pas une option.
La plupart des algorithmes de compression se rapprocheront de l'entropie minimale nécessaire pour encoder les entiers, par exemple, codage de Huffman, mais l'accédant comme un tableau sera non trivial. P>
Le but est que je voudrais l'écrire plus tard dans un fichier, j'ai donc besoin de bitpack d'abord pour économiser de l'espace disque.
Si vous souhaitez minimiser l'utilisation du disque, vous devez rechercher une bibliothèque de compression au lieu de rouler le vôtre.
Eh bien, je suis en train de rouler le mien en train de rouler, d'où la question :).
Je suis d'accord avec Keraba que vous devez utiliser quelque chose comme le codage de Huffman ou peut-être l'algorithme de Lempel-ZIV-WELCH. Le problème avec l'emballage de la manière dont vous parlez est que vous avez deux options:
La première option est relativement facile à mettre en œuvre, mais va vraiment perdre beaucoup d'espace à moins que tous les entiers ne soient plutôt petits. P>
La deuxième option a l'inconvénient majeur que vous avez Transmettre des changements de N en quelque sorte dans la sortie Bitstream. Par exemple, chaque valeur devra avoir une longueur associée à celle-ci. Cela signifie que vous stockez deux entiers (bien que des entiers plus petits) pour chaque valeur d'entrée. Il y a une bonne chance que vous augmentez la taille du fichier avec cette méthode. P>
L'avantage de Huffman ou de LZW est qu'ils créent des livres de codes de manière à ce que la longueur des codes puisse être dérivée du bits de sortie de la sortie. sans stocker réellement les longueurs. Ces techniques vous permettent de devenir très proches de la limite de Shannon. P>
J'ai décidé de donner votre idée originale (constante N, supprimer des bits inutilisés) un essai pour le plaisir et voici la mise en œuvre naïve que je suis venu Avec: P>
#include <sys/types.h> #include <stdio.h> int pack(int64_t* input, int nin, void* output, int n) { int64_t inmask = 0; unsigned char* pout = (unsigned char*)output; int obit = 0; int nout = 0; *pout = 0; for(int i=0; i<nin; i++) { inmask = (int64_t)1 << (n-1); for(int k=0; k<n; k++) { if(obit>7) { obit = 0; pout++; *pout = 0; } *pout |= (((input[i] & inmask) >> (n-k-1)) << (7-obit)); inmask >>= 1; obit++; nout++; } } return nout; } int unpack(void* input, int nbitsin, int64_t* output, int n) { unsigned char* pin = (unsigned char*)input; int64_t* pout = output; int nbits = nbitsin; unsigned char inmask = 0x80; int inbit = 0; int nout = 0; while(nbits > 0) { *pout = 0; for(int i=0; i<n; i++) { if(inbit > 7) { pin++; inbit = 0; } *pout |= ((int64_t)((*pin & (inmask >> inbit)) >> (7-inbit))) << (n-i-1); inbit++; } pout++; nbits -= n; nout++; } return nout; } int main() { int64_t input[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}; int64_t output[21]; unsigned char compressed[21*8]; int n = 5; int nbits = pack(input, 21, compressed, n); int nout = unpack(compressed, nbits, output, n); for(int i=0; i<=20; i++) printf("input: %lld output: %lld\n", input[i], output[i]); }
Je ne pense pas que vous puissiez éviter d'itération à travers les éléments. Le codage d'Afaik Huffman nécessite les fréquences des "symboles", qui sauf si vous connaissez les statistiques du "processus" générant les entiers, vous devrez calculer (en itérant à tous les éléments). P>
Lorsque l'arbre Huffman est prédéfini, cela signifie que vous connaissez déjà les "statistiques" du processus de génération (comme je l'ai écrit). Désolé si mon explication n'était pas claire à ce sujet.
Si vous avez des tailles fixes, par exemple Vous savez que votre numéro est 38 bits plutôt que 64, vous pouvez créer des structures à l'aide de spécifications de bits. Amusant vous avez également des éléments plus petits pour vous installer dans l'espace restant.
struct example { /* 64bit number cut into 3 different sized sections */ uint64_t big_num:38; uint64_t small_num:16; uint64_t itty_num:10; /* 8 bit number cut in two */ uint8_t nibble_A:4; uint8_t nibble_B:4; };
Mais ces structures utiliseraient plus d'espace que le mon int [] code>! Le but est de gagner de l'espace en déplaçant des bits autour (éventuellement) en place.
Aujourd'hui, j'ai publié: Il implémente un aléatoire Conteneur d'accès où les articles sont emballés au niveau du bit. En d'autres termes, il agit comme si vous pouviez manipuler un par exemple. uint9_t code> ou
uint17_t code> tableau: p>
À partir de la mise en œuvre de Jason B, j'ai finalement écrit ma propre version qui traite des blocs de bit au lieu de bits simples. Une différence est que c'est LSB: il commence à partir des bits de sortie les plus bas allant au plus haut. Cela ne rend que plus difficile de lire avec un vidage binaire, comme Linux XXD -B code>. Comme un détail,
int * code> peut être de manière trivialement modifiée en
intz_t * code>, et il devrait même mieux être
non signé code>. J'ai déjà testé cette version avec quelques millions de tableaux et il semble solide, donc je partage le reste:
Par curiosité, qu'est-ce que vous avez utilisé à la fin?
Rien de vraiment, le projet que c'était destiné à mort :). Mais des réponses ici et mes besoins d'origine, je finirais probablement d'utiliser des masques et des compensations informatiques à la main. Peut-être utiliser des modèles intelligents aussi.
3 ans après votre demande, j'ai finalement répondu à votre question en mettant en œuvre un conteneur d'accès aléatoire où des éléments sont bien emballés. Voir ma réponse: Stackoverflow.com/a/18038506/216063