Y at-il jamais un bon moment pour utiliser int32 au lieu de SINT32 dans Google Protocol Buffers?

StackOverflow https://stackoverflow.com/questions/765916

  •  12-09-2019
  •  | 
  •  

Question

Je l'ai lu sur Google Protocol Buffers récemment, ce qui permet une variété des types de valeur scalaire à utiliser dans les messages.

Selon leur documentation , il y a trois types de variables primitives entiers -Longueur - int32, uint32 et sint32. Dans leur documentation, ils notent que int32 est « Inefficace pour l'encodage des nombres négatifs - si votre champ est susceptible d'avoir des valeurs négatives, utilisez sint32 à la place. » Mais si vous avez un champ qui n'a pas de chiffres négatifs, je suppose que uint32 serait un meilleur type à utiliser que int32 de toute façon (en raison du bit supplémentaire et diminution du coût du processeur de traitement des nombres négatifs).

Alors, quand serait int32 être un bon scalaire à utiliser? La documentation est ce qui implique qu'il est plus efficace que lorsque vous obtenez rarement des nombres négatifs? Ou est-il toujours préférable d'utiliser sint32 et uint32, selon le contenu du champ?

(Les mêmes questions s'appliquent aux versions 64 bits de ces scalaires ainsi:. int64, uint64 et sint64, mais je les ai laissés de la description du problème pour des raisons de lisibilité)

Était-ce utile?

La solution

Je ne suis pas familier avec Google Protocol Buffers, mais mon interprétation de la documentation est:

  • utilisation uint32 si la valeur ne peut pas être négatif
  • utilisation sint32 si la valeur est à peu près aussi susceptible d'être négatif non (pour une définition floue de « comme susceptible d'être »)
  • utilisation int32 si la valeur pourrait être négative, mais qui est beaucoup moins probable que la valeur étant positive (par exemple, si l'application utilise parfois -1 pour indiquer une erreur ou une valeur « inconnue », ce qui est une situation relativement rare)

Voici ce que les documents ont à dire au sujet des encodages ( http: / /code.google.com/apis/protocolbuffers/docs/encoding.html#types ):

  

il y a une différence importante entre les types int signés (et de sint32 sint64) et les types int « standard » (et de int32 int64) en ce qui concerne le codage des nombres négatifs. Si vous utilisez int32 ou int64 comme type pour un nombre négatif, le varint résultant est toujours dix octets - il est, effectivement, traité comme un entier non signé très grand. Si vous utilisez l'un des types signés, le varint résultant utilise le codage ZigZag, ce qui est beaucoup plus efficace.

     

codant pour ZigZag cartes de nombres entiers signés à des entiers non signés de sorte que des nombres avec une petite valeur absolue (par exemple, -1) ont une faible valeur codée varint aussi. Il fait cela d'une manière qui « zig-zags » d'avant en arrière à travers les nombres entiers positifs et négatifs, de sorte que -1 est codé en tant que 1, 1 est codé en tant que 2, -2 est codé sous la forme 3, et ainsi de suite ...

Il semble donc que même si votre utilisation de nombres négatifs est rare, aussi longtemps que l'ampleur des chiffres (y compris les numéros non-négatifs) vous passez dans le protocole est sur le petit côté, vous pourriez être mieux en utilisant sint32. Si vous n'êtes pas sûr, le profilage serait dans l'ordre.

Autres conseils

Il y a très peu de bonnes raisons d'utiliser toujours int * plutôt que sint *. L'existence de ces types supplémentaires est le plus probable pour des raisons historiques, en arrière des raisons de compatibilité, qui tamponne Protocole essaie de maintenir même à travers ses propres versions de protocole.

Ma meilleure estimation est que dans la première version qu'ils entiers négatifs codés dumbly dans la représentation du complément de 2, ce qui nécessite l'encodage varint au maximum la taille de 9 octets (sans compter l'octet de type supplémentaire). Ensuite, ils ont été coincés avec ce codage pour ne pas briser l'ancien code et qui sérialisations déjà utilisé. , Ils ont besoin afin d'ajouter un nouveau type de codage, sint *, pour obtenir un meilleur encodage de taille variable pour les nombres négatifs sans casser le code existant. Comment les concepteurs ne se rendent pas compte de cette question de la get-go est tout à fait au-delà de moi.

Le codage varint (sans spécification de type, ce qui nécessite une plus byte) peut coder pour une valeur de nombre entier non signé dans le nombre d'octets suivant:

[0, 2 ^ 7): un octet

[^ 2 7, 2 ^ 14): deux octets

[^ 2 14, 2 ^ 21): trois octets

[^ 2 21, 2 ^ 28): quatre octets

[^ 2 28, 2 ^ 35): cinq octets

[^ 2 35, 2 ^ 42): six octets

[^ 2 42, 2 ^ 49): sept octets

[^ 2 49, 2 ^ 56): huit octets

[^ 2 56, 2 ^ 64): neuf octets

Si vous voulez encoder faible amplitude des entiers négatifs, alors vous aurez compacte de la même besoin de « utiliser jusqu'à » un bit pour indiquer le signe. Vous pouvez le faire à travers un bit de signe explicite (à une position réservée) et la représentation de grandeur. Ou, vous pouvez faire le codage zig zag, ce qui fait effectivement la même chose en changeant gauche l'ampleur de 1 bit et en soustrayant 1 pour les nombres négatifs (donc bit le moins significatif indique le signe: Evens sont non-négatif, les chances sont négatives).

De toute façon, la coupe sur les points où positif entiers nécessitent plus d'espace est maintenant un facteur de 2 précédemment:

[0, 2 ^ 6): un octet

[2 ^ 6, 2 ^ 13): deux octets

[^ 2 13, 2 ^ 20): trois octets

[^ 2 20, 2 ^ 27): quatre octets

[^ 2 27, 2 ^ 34): cinq octets

[^ 2 34, 2 ^ 41): six octets

[^ 2 41, 2 ^ 48): sept octets

[^ 2 48, 2 ^ 55): huit octets

[^ 2 55, 2 ^ 63): neuf octets

Pour le cas à utiliser int * sur sint *, les nombres négatifs devraient être extrêmement rares, mais possible, et / ou les valeurs positives les plus courantes que vous attendez d'encoder devraient tomber à droite autour d'un des coupe plus points qui conduit à un codage plus grand dans sint * par opposition aux int * (par exemple, - 2 ^ 6 vs 2 ^ 7 conduisant à 2x codant pour la taille)

.

En gros, si vous allez avoir des numéros où certains peuvent être négatif, par l'utilisation par défaut sint * plutôt que int *. int * sera très rare même supérieure et sera généralement pas la peine supplémentaire pensé que vous devez consacrer à juger si cela vaut la peine ou non à mon humble avis.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top