2010-11-16 4 views
5

J'ai posé des questions sur la manipulation hexagonale et bitwise (ici et ailleurs) pour la semaine passée en essayant d'envelopper ma tête autour de leur représentation en Java. Après beaucoup de googling et de chagrin, je dois demander une dernière fois comment effectuer une arithmétique logique sur des bits qui devraient être non signés, mais qui sont représentés comme étant signés en Java.Effectuer des décalages à gauche bit à bit sur les données "signées" en Java - préférable de passer à JNI?

Ok: Je suis en train de transférer un programme C# vers Java. Le programme traite de la manipulation de bitmap, et en tant que telle une grande partie des données dans l'application est représentée par byte, un entier non signé de 8 bits. Il existe de nombreuses suggestions pour utiliser à la place le type de données short en Java afin d '"imiter" le plus près possible l'entier non signé de 8 octets.

Je ne crois pas que ce soit possible pour moi car le code C# effectue de nombreuses opérations de décalage et d'ET avec mes données d'octets. Par exemple, si data est un tableau d'octets, et ce bloc de code existe en C#:

int cmdtype = data[pos] >> 5; 
int len = (data[pos] & 0x1F) + 1; 

if (cmdtype == 7) 
{ 
    cmdtype = (data[pos] & 0x1C) >> 2; 
    len = ((data[pos] & 3) << 8) + data[pos + 1] + 1; 
    pos++; 
} 

Ce n'est pas une simple question de simplement coulée data comme short et se fait avec lui pour le faire fonctionner en Java . En ce qui concerne la logique, l'exigence que mes données restent en 8 bits non signées est significative; 16 bits non signé serait visser des maths comme ci-dessus. Suis-je ici? En effet, après avoir précédemment "faux casting" byte avec 0XFF et char en Java et ne pas obtenir les bons résultats, je crains de tomber dans une impasse.

Maintenant, dans une autre partie du code, j'effectue une manipulation de pixels bitmap. Comme c'est un processus de longue durée, j'ai décidé de faire un appel au code natif via JNI. Je me suis récemment rendu compte que je pouvais utiliser le type de données uint8_t et obtenir la représentation la plus proche du type de données C# byte.

La solution pour faire fonctionner toutes mes fonctionnalités dépendantes des données dans JNI? Cela semble très inefficace, à la fois pour réécrire et pour effectuer. La solution est-elle de refaire les maths en Java pour que la logique reste la même? Que semble droite, mais a le potentiel d'induire un anévrisme, pour ne pas mentionner les mathématiques défectueuses.

J'apprécie toutes les suggestions.

+0

Pourriez-vous ajouter des commentaires indiquant ce que C# fait par rapport à ce que Java fait à chaque étape de l'extrait de code? Je ne pense pas que je puisse déchiffrer tous les endroits dans ce code où vous pourriez voir des problèmes par moi-même. –

+0

Je n'ai rien que je classerais comme une réponse, mais si vous faites beaucoup de twittling, je suggère d'écrire une classe simple en utilisant JNI qui fait cela plutôt que de faire beaucoup de casting. Cela nuira aux performances, au débogage et à la lisibilité. Peu importe, je continuerais à profiler le code avant de tout convertir en JNI. Concentrez-vous sur les domaines qui en ont le plus besoin. –

+0

@John Je ne propose pas de tout refaire dans JNI - je me demandais juste si c'était une solution viable. – GJTorikian

Répondre

3

Juste une note: Vous ne pouvez pas lancer directement à short, car les nombres négatifs seront logiquement prolongés.

C'est, l'octet 1111 1101 (-5) lorsqu'il est directement jeté à short se traduira par 1111 1111 1111 1101 (-5), non 0000 0000 1111 1101 (253).Vous devez supprimer les principaux ceux avec une opération ET lorsque vous lancez:

short shortValue = ((short)(byteValue)) & 0xFF; 

Je sais manipulation de bits complexe comme cela est possible, parce que je l'ai fait cette chose exacte dans la gestion d'un héritage protocole de messagerie binaire avec une application Java Swing . Je recommanderais fortement de faire abstraction de tout cela afin que vous ne deviez y faire face qu'une seule fois. Que cela signifie que vous enveloppez vos "octets" dans une classe pour les stocker en tant que shorts et gérer les opérations de conversion ou définir un utilitaire statique qui effectue la conversion et l'opération de bits en une seule passe, de sorte que vous stockez toujours des octets.

+0

Je pense que mon cerveau est juste frit. si je fais le flip et le cast mes maths bit à bit resteront les mêmes? Comme je l'ai dit précédemment, j'étais "faux casting" avec la technique exacte que vous avez décrite, utilisant seulement un caractère à la place. – GJTorikian

2

Java a le >>> (notez les trois caractères ">", pas seulement deux) opérateur de droite non signé. Cela devrait conserver au moins le décalage de droite du style C# (les bits supérieurs sont effacés à zéro, pas remplis de signe).

En ce qui concerne la conversion en 'court', C# convertit tous ces octets en entiers de 32 bits avant de les décaler de toute façon. Le seul truc est que C# fait un cast non signé (il remplit seulement les 24 bits supérieurs avec 0, quelle que soit la valeur du bit 7). Si vous avez jeté à court en Java, vous devriez juste être en mesure de dire quelque chose comme:

short shortCast = ((short)byteVal) & 0xff; 
short shiftedShortCast = shortCast << whatever; 
+0

Il est vrai que C# convertit en un 'int', mais il a aussi le concept de types non signés, qui empêchent les principaux de s'étendre dans ce qui serait des nombres négatifs. – jdmichal

+0

Bon point @jdmichal. Je vais éditer la réponse. –

Questions connexes