2010-02-04 3 views
1

자바에서 과학적 이중을 십진수로 변환하려고합니다. X86 (리틀 엔디안) 컴퓨터에서 실행중인 서버 (C++로 코딩 됨)에서 값을 보내고 있으며 클라이언트 (데이터를 자바로 코딩)로 보내기 전에 변환을 위해 htonl, ntohl 메소드를 사용하고있었습니다. 하지만 지금은 LE와 같은 전환없이이 가치를 전달해야합니다. 변환은 클라이언트 (자바) 측에서 수행됩니다. 다른 유형은 올바르게 변환 될 수 있지만 이중에서는 존재하지 않습니다. 클라이언트가 double 유형을 수신하면이 값을 올바르게 읽을 수 없습니다. 다음은 이중 변환을위한 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));  
} 

위의 모든 단계를 완료 한 후 서버에서 0.3을 보냈다면 9.534475227E-315를 얻었습니다.
감사합니다.

+1

무엇을 찾았나요? 너 무슨 짓을 한거야? 당신이하고 싶은 것을 보여주세요. – tangens

+0

나는 9.534475227E-315와 같은 값을 가지고 있으며이를 0.3으로 변환하고 싶습니다. 왜 0.3입니까? 나는 서버에서 클라이언트로 0.3을 보냈고 클라이언트에서이 값을 읽었을 때 9.534475227E-315 – Aykut

+0

변환 방법에 대한 자세한 정보를 제공해야합니다. – Mark

답변

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

나는 리틀 엔디안 형식으로 서버에서 데이터를 보낼 때, 나는 자바에서이 코드를 빅 endian 형식의 값으로 들어오는 리틀 엔디안 형식의 값을 변환 할 수 있습니다.

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

0

서버에서 클라이언트로 0.3을 보내고 9.534475227E-315를 얻은 경우 마지막으로해야 할 일은 해당 값을 다시 0.3으로 변환하는 것입니다. 반환 값은 f-p 조건에서 0에 매우 가깝고 보내기 및 반환 프로세스에서 약간의 오류를 나타냅니다.

귀하의 질문에 당황 스럽지만 Java가 Decimal 클래스를 구현했지만 Java 지식이 오래되고 부족하다는 것을 알지 못했습니다. BigDecimal을 의미할까요? 아니면 완전히 다른 물고기 주전자가 될 부동 소수점 숫자의 문자열 형식을 변환하고 있습니까?

1

부호있는 산술 및 잘못된 비트 값 사용과 같은 여러 가지 방법으로 변환에 결함이 있습니다. format을 학습하고 glossary 항목에 표시된 접근 방식을 살펴보십시오.

+0

귀하의 링크가 나를 위해 정말로 도움이되었습니다. 문제를 해결했습니다. 여기에 내 해결책을 쓸 것입니다. – Aykut

1

"과학 표기법"이라는 용어를 사용하면 "3.0e-1"과 같은 텍스트 데이터를 처리하고 있음을 알 수 있습니다. 그러나 나는 이해한다고 생각한다.

문제는 비 자바 단어 순서로 작성된 이진 데이터를 읽는 것 같습니다. 그러나 정수가 빅 엔디안으로 쓰여지는 이유는 무엇입니까? 왜 그런 이상한 방식으로 책을 읽나요? 컴파일러가 'int'에 대해 불평하지 않습니까? 문제를 숨기고있는 것 같습니다. (EDIT : 내 오류 - 이중 64 비트에 붙어있었습니다.)

모든 사용자가 데이터의 16 진수 덤프를 보는 것이 유용 할 것입니다. 바이트가 뒤집혀 졌습니까, 아니면 그냥 단어입니까?

아마도이 코드는 영감을 줄 것입니다. '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

흠, 나는 재미있는 슬립 업을 만들어 그것을 복제했습니다. 승진을위한 규칙 ... – gary

+0

내가 왜 this.we와 같은 뭔가를해야만하는지 설명하자. 우리는 솔라리스 sparc os를 C++로 코딩하고있다. 우리 프로그램의 서버 측과 클라이언트 측을 코딩하고 있지만 클라이언트 측은 마지막 mounths에서 java로 코딩되어있다. 그런 다음 x86 지원에 대한 새로운 요청을 받았습니다 (Linux Bas 솔라리스 x86 OS) 플랫폼을 지원합니다. 그런 다음 저는 솔라리스에서 리눅스로, 솔라리스 sparc에서 솔라리스 x86으로 포트를 시작했습니다. 서버 측에서 x86 머신에서 실행될 때 우리는 엔디안 문제를 해결했습니다. 서버 측은 500000 라인의 코드를 가지고 있으며 클라이언트 (java) 측에서 시스템 아키텍처에 따라 수치 데이터를 변환하기로 결정했습니다. – Aykut

+1

귀하의 원래 질문에 귀하는 전환없이 데이터를 전송하고 있다고하셨습니다. 모든 서버가 동일한 형식으로 전송됩니까? 16 진수와 숫자 값을 가진 짧은 데이터 덤프는 많은 도움이됩니다. 0.3 (0x3fd3333333333333)을 보내고 심각한 혼란없이 9.534475227E-315 (0x0000000073066666)을 얻을 방법이 없습니다. 나는 내 프로그램이 전환의 방법을 보여줄 수 있어야한다고 생각한다. 나는 혼란을 없애기 위해 그것을 청소했다. – gary

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