двойная научная запись к десятичной записи в Java - PullRequest
1 голос
/ 04 февраля 2010

Я пытаюсь преобразовать научный двойной в десятичный двойной в Java. Я отправляю значение с сервера (написанного на C ++), работающего на машине X86 (с прямым порядком байтов), и я использовал методы преобразования htonl, ntohl перед отправкой данных клиенту (написано на Java). Но теперь я должен отправить это значение без преобразования, как LE в BE. Covering делается на стороне клиента (Java). Другой тип может быть преобразован правильно, но для двойного этого нет. Когда клиент получает тип 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));      
}

После всех этих шагов я получил 9.534475227E-315, если отправил 0.3 с сервера.
Спасибо и всего наилучшего.

Ответы [ 6 ]

3 голосов
/ 04 февраля 2010

Звучит так, будто вы неверно читаете значение с клиента, но в любом случае 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 голос
/ 06 февраля 2010

Не катите свой собственный бит, вертя так.Это в стандартном 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);
}
1 голос
/ 05 февраля 2010

Использование термина «научная нотация» предполагает, что вы имеете дело с текстовыми данными, которые выглядят как «3.0e-1».Но я думаю, что понимаю.

Кажется, проблема в том, что мы просто читаем двоичные данные, записанные в не-Java-порядке.Тем не менее, почему целые числа пишутся с прямым порядком байтов, а двойные числа записываются с прямым порядком байтов?И почему ты читаешь таким странным образом?Ваш компилятор не жалуется на int?Это могло скрывать проблему.( РЕДАКТИРОВАТЬ : моя ошибка - я застрял на 64 битах для двойного)

Было бы полезно, чтобы все видели шестнадцатеричный дамп ваших данных.Перевернуты ли байты или просто слова?

Может быть, этот код послужит источником вдохновения.Пожалуйста, извините за использование '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);
        }
    }
}
1 голос
/ 04 февраля 2010

Ваше преобразование имеет недостатки в нескольких отношениях, включая использование знаковых арифметических и неправильных битовых значений. Вы можете изучить формат и взглянуть на подход, показанный в этой записи глоссарий .

0 голосов
/ 09 февраля 2010

Я решил мой вопрос и спасибо всем за помощь.Очень признателен.Итак, вот решение.

  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.

0 голосов
/ 04 февраля 2010

Если вы отправили 0.3 с сервера на клиент и вернулись 9.534475227E-315, последнее, что вам нужно сделать, - снова преобразовать это значение в 0.3.Возвращаемое значение очень близко к 0 в терминах fp и указывает на некоторую ошибку в процессе отправки и возврата.

Я озадачен вашим вопросом, я не знал, что Java реализовал класс Decimal, но затем мой Javaзнания старые и скудные.Возможно, вы имеете в виду BigDecimal?Или вы конвертируете строковые форматы чисел с плавающей запятой, что было бы совершенно другим котлом с рыбой?

...