2010-02-04 91 views
1

我想將科學雙數轉換爲java中的十進制雙精度。我發送一個在X86(小端)機器上運行的服務器(用C++編碼)的值,並且在將數據發送到客戶機(在java上編碼)之前,我使用htonl,ntohl方法進行轉換。但是現在,我必須發送這個值,而不像LE那樣轉換爲BE。正在客戶端(java)端進行覆蓋。其他類型可以正確轉換,但雙重,這是不存在的。當客戶端收到雙精度型時,該值無法正確讀取。這是我的雙重轉換的Java代碼。雙重科學記數法在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));  
} 

經過所有這些步驟,我得到9.534475227E-315,如果我從服務器發送0.3。
感謝和問候。

+1

你發現了什麼?你嘗試了什麼?請舉一個你喜歡做什麼的例子。 – tangens 2010-02-04 12:26:33

+0

我有一個像9.534475227E-315的值,我想將其轉換爲0.3。爲什麼0.3?因爲我從服務器發送0.3到客戶端,當我從客戶端讀取這個值時,我得到了9.534475227E-315 – Aykut 2010-02-04 12:29:40

+0

您需要提供更多關於如何嘗試轉換的信息 – Mark 2010-02-04 12:31:03

回答

0

我解決了我的問題,並感謝大家的幫助。非常感激。所以這裏是解決方案。

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)); } 

當我在小尾數格式從服務器發送數據,我可以進來小尾數格式的值轉換爲大端格式化值與此代碼Java編寫的。

3

這聽起來像你正在閱讀的錯誤值從客戶端,但在任何情況下,NumberFormat的是你的朋友:) http://java.sun.com/j2se/1.5.0/docs/api/index.html?java/text/NumberFormat.html

編輯:考慮到你發佈的代碼示例中,我不得不同意@trashgod表示您的轉換代碼有缺陷。 Perhap DataInputStream可以幫助 - >http://java.sun.com/javase/6/docs/api/java/io/DataInputStream.html

+1

'java.nio.ByteBuffer'的'order()'方法在這種情況下也是有益的。http://java.sun.com/javase/6/docs/api/java/nio/ByteBuffer.html – trashgod 2010-02-04 22:38:10

0

如果您從服務器發送0.3到客戶端並返回9.534475227E-315,那麼您應該做的最後一件事是將該值再次轉換爲0.3。返回的值在f-p中非常接近0,並且指示發送和返回過程中有一些錯誤。

我對你的問題感到困惑,我不知道Java實現了一個Decimal類,但是後來我的Java知識已經老了而且很少。你可能是指BigDecimal?還是你轉換浮點數的字符串格式,這將是一個完全不同的水壺?

1

您的轉換在多個方面存在缺陷,包括使用帶符號的算術和不正確的位值。您可以研究format並查看此glossary條目中顯示的方法。

+0

感謝trashgod你的鏈接對我來說真的很有幫助我解決了這個問題我會在這裏寫我的解決方案 – Aykut 2010-02-06 11:23:27

1

您使用術語「科學記數法」sorta表示您處理的文本數據看起來像「3.0e-1」。但我想我明白了。

看來問題在於讀取以非java字順序編寫的二進制數據。然而,爲什麼這些整數寫成big-endian,但雙打寫成little-endian呢?你爲什麼以這種奇怪的方式閱讀?你的編譯器不會抱怨'int'嗎?它可能一直在隱藏一個問題。 (編輯:我的錯誤 - 我被困在64位的雙倍)

這將是有用的每個人都看到數據的十六進制轉儲。是字節翻轉,還是隻是字?

也許這段代碼會提供一些靈感。請原諒'讓 - 做 - 完成'使用變量。

// 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

嗯,我做了一個有趣的滑動,並且重複了它。促銷規則... – gary 2010-02-05 03:37:24

+0

讓我解釋爲什麼我必須做這樣的事情。我們正在編寫solaris sparc os,用於我們程序的服務器和客戶端的C++,但客戶端已經用java編碼在最後的mounths中。然後我們得到了一個關於支持x86的新請求(包括linux bas ed和solaris x86操作系統)平臺。然後我開始將服務器端從solaris到linux和solaris sparc移植到solaris x86。當運行在x86機器上的服務器端時,我們會產生endian問題。因此,服務器端有500000行代碼,我們決定根據客戶端(java)端的系統架構轉換數字數據。 – Aykut 2010-02-06 11:18:27

+1

您的原始問題表明您發送的數據未經過轉換。你所有的服務器都發送相同的格式嗎?一個(短)數據轉儲,十六進制和數字值,將有很大幫助。我沒有辦法發送0.3(0x3fd3333333333333)並得到9.534475227E-315(0x0000000073066666)沒有一些嚴重的混淆。我相信我的程序應該幫助你展示轉換的方法,一旦你知道你正在轉換什麼。我清理它以消除一些混淆。 – gary 2010-02-06 17:13:44

1

不要把你自己的位弄亂。它在標準API中。請參閱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); 
}