2010-02-04 5 views
1

Je suis en train de convertir le double scientifique en double décimal en Java. J'envoie une valeur du serveur (codé sur C++) qui fonctionne sur la machine X86 (little endian) et j'utilise les méthodes htonl, ntohl pour la conversion avant d'envoyer les données au client (codé sur java). Mais maintenant, je dois envoyer cette valeur sans conversion comme LE à BE. La conversion est effectuée sur le côté client (Java). L'autre type peut être converti correctement mais pour le double, ce n'est pas présent. Lorsque le client reçoit un type double, cette valeur ne peut pas être lue correctement. Voici mon code java pour la double conversion.double notation scientifique à la notation décimale en Java

protected int readInt(InputStream stream) throws IOException { 
    int i0 = read(stream); 
    int i1 = read(stream); 
    int i2 = read(stream); 
    int i3 = read(stream); 
    int i=(i0 << 24) + (i1 << 16) + (i2 << 8) + (i3 << 0); 
    return i; 
} 
protected double readDouble(InputStream stream) throws IOException { 
    int i0 = readInt(stream); 
    int i1 = readInt(stream); 
    return Double.longBitsToDouble(((long)i0 << 32) + (i1 & 0xffffffffL));  
} 

Après toutes ces étapes, je me suis 9.534475227E-315 si j'ai envoyé 0,3 du serveur.
Merci et salutations.

+1

Qu'avez-vous trouvé? Qu'avez-vous essayé? S'il vous plaît donnez un exemple pour ce que vous aimez faire. – tangens

+0

J'ai une valeur comme 9.534475227E-315 et je veux convertir cela en 0.3. Pourquoi 0,3? parce que j'ai envoyé 0.3 du serveur au client et quand j'ai lu cette valeur du client, j'ai obtenu 9.534475227E-315 – Aykut

+0

Vous devez fournir plus d'informations quant à la façon dont vous essayez de convertir – Mark

Répondre

0

J'ai résolu la question et je vous remercie pour votre aide. Très appréciée. Alors, voici la solution.

protected double readDouble(InputStream stream) throws IOException { 

    return Double.longBitsToDouble(((long) read(stream) & 0xff) 
           | ((long) (read(stream) & 0xff) << 8) 
           | ((long) (read(stream) & 0xff) << 16) 
           | ((long) (read(stream) & 0xff) << 24) 
           | ((long) (read(stream) & 0xff) << 32) 
           | ((long) (read(stream) & 0xff) << 40) 
           | ((long) (read(stream) & 0xff) << 48)      
           | ((long) (read(stream) & 0xff) << 56)); } 

Lorsque j'envoie un données du serveur au format petit-boutiste, je peux convertir peu de valeur au format endian entrant à grande valeur formatée endian avec ce code en Java.

3

On dirait que vous lisez la mauvaise valeur du client, mais en tout cas, NumberFormat est votre ami :) http://java.sun.com/j2se/1.5.0/docs/api/index.html?java/text/NumberFormat.html

EDIT: considérant l'exemple de code que vous avez publié, je suis d'accord avec @trashgod que votre code de conversion est défectueux. Perhap DataInputStream peut vous aider ->http://java.sun.com/javase/6/docs/api/java/io/DataInputStream.html

+1

La méthode 'order()' de 'java.nio.ByteBuffer' peut aussi être bénéfique dans ce contexte: http://java.sun.com/javase/6/docs/api/java/nio/ByteBuffer.html – trashgod

0

Si vous avez envoyé 0.3 du serveur au client et que vous avez récupéré 9.534475227E-315, la dernière chose que vous devriez faire est de convertir cette valeur en 0.3 à nouveau. La valeur retournée est très proche de 0 en termes de f-p, et indique une erreur dans le processus d'envoi et de retour.

Je suis perplexe à votre question, je ne savais pas que Java a implémenté un cours décimal, mais alors mes connaissances Java sont anciennes et rares. Voulez-vous dire un BigDecimal? Ou convertissez-vous des formats de chaîne de nombres à virgule flottante, ce qui serait une bouilloire de poisson complètement différente?

1

Votre conversion comporte plusieurs failles, notamment l'utilisation de valeurs arithmétiques signées et incorrectes. Vous pourriez étudier le format et regarder l'approche montrée dans cette entrée glossary.

+0

Merci, trashgod, votre lien m'a été d'une aide précieuse, j'ai résolu le problème, je vais écrire ma solution ici – Aykut

1

L'utilisation du terme "notation scientifique" suggère que vous avez affaire à des données textuelles qui ressemblent à "3.0e-1". Mais je pense que je comprends.

Il semble que le problème consiste simplement à lire des données binaires écrites dans un ordre de mots non-java. Mais pourquoi les entiers sont-ils écrits en big-endian, alors que les doubles sont écrits en little-endian? Et pourquoi lisez-vous d'une manière si étrange? Est-ce que votre compilateur ne se plaint pas de l'int? Cela a peut-être caché un problème. (EDIT: mon erreur - J'étais coincé sur 64 bits pour le double)

Il serait utile pour tout le monde de voir un vidage hexadécimal de vos données. Les octets sont-ils retournés ou juste les mots?

Peut-être que ce code vous inspirera. S'il vous plaît excusez l'utilisation des variables "get-r-done".

// convert CLI argument to double, write to file, and read back 
// without args, default is "0.3" 
// should try negative numbers! 

import java.io.*; 

public class BinaryFile { 

    public static void main(String[] args) { 

     String strFilePath = "WordFlippedDouble"; 
     boolean WRITEOP = true; 
     double d, dd = 0.3; 
     long ddFlip; 

     if(args.length > 0) { 
      dd = Double.valueOf(args[0]); 
     } 
     System.out.println("Starting with " + dd + " looks like " + 
      Long.toHexString(Double.doubleToLongBits(dd))); 

     if(WRITEOP) { 
      ddFlip = Double.doubleToLongBits(dd); 
      ddFlip = (ddFlip<<32) | ((ddFlip>>32) & 0xFFFFFFFFL); 
      System.out.println("WRITE: (flipped) looks like " + Long.toHexString(ddFlip)); 
      try { 
       FileOutputStream fout = new FileOutputStream(strFilePath); 
       DataOutputStream dout = new DataOutputStream(fout); 
       dout.writeLong(ddFlip); 
       dout.close(); 
      } catch (Exception e) { 
       System.out.println("ERROR: " + e.getMessage()); 
      } 
     } 

     if(false) return;    // testing 

     try { 
      FileInputStream fin = new FileInputStream(strFilePath); 
      DataInputStream din = new DataInputStream(fin); 
      ddFlip = din.readLong(); 
      d = Double.longBitsToDouble((ddFlip<<32) | ((ddFlip>>32) & 0xFFFFFFFFL));              
      System.out.println("READ: " + Long.toHexString(ddFlip) + " converts to " + 
       d + " DIFF: " + (dd-d)); 
      din.close(); 
     } catch(FileNotFoundException e) { 
      System.out.println("FileNotFoundException : " + e); 
     } 
     catch(IOException e) { 
      System.out.println("IOException : " + e); 
     } 
    } 
} 
+0

Hmmm, j'ai fait une erreur intéressante, et je l'ai dupliquée. règles pour la promotion ... – gary

+0

laissez-moi vous expliquer pourquoi je dois faire quelque chose comme ça.Nous codons sur Solaris sparc os en C++ pour le côté serveur et client de notre programme, mais le côté client a été codé avec Java dans les derniers mois. Ensuite, nous avons eu une nouvelle demande sur la prise en charge de x86 (y compris linux bas plates-formes ed et solaris x86). Ensuite, j'ai commencé à porter le côté serveur de Solaris à Linux et Solaris Sparc à Solaris x86. Lorsque le côté serveur s'exécutait sur des machines x86, nous avons encombré les questions endian.so, côté serveur a 500 000 lignes de code et nous avons décidé de convertir les données numériques en fonction de l'architecture du système côté client (java). – Aykut

+1

Votre question initiale indiquait que vous envoyiez les données sans conversion. Tous vos serveurs envoient-ils le même format? Un vidage de données (court), avec une valeur hexadécimale et numérique, aiderait beaucoup. Je ne vois aucun moyen d'envoyer 0.3 (0x3fd3333333333333) et obtenir 9.534475227E-315 (0x0000000073066666) sans un mélange sérieux. Je crois que mon programme devrait aider à montrer la méthode de conversion, une fois que vous savez ce que vous convertissez. Je l'ai nettoyé pour enlever une certaine confusion. – gary

1

Ne roulez pas votre propre trépidation comme ça. C'est dans l'API standard. Voir java.nio.ByteBuffer.

protected int readInt(InputStream stream) throws IOException { 
    ByteBuffer buffer = ByteBuffer.allocate(Integer.SIZE/Byte.SIZE); 
    //buffer.order(ByteOrder.LITTLE_ENDIAN); // optional 
    stream.read(buffer.array()); 
    return buffer.getInt(0); 
} 
protected double readDouble(InputStream stream) throws IOException { 
    ByteBuffer buffer = ByteBuffer.allocate(Double.SIZE/Byte.SIZE); 
    //buffer.order(ByteOrder.LITTLE_ENDIAN); // optional 
    stream.read(buffer.array()); 
    return buffer.getDouble(0); 
} 
Questions connexes