2010-02-04 92 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); 
}