Преобразование 80-битной расширенной точности в java

Я работаю над программой, которая конвертирует действительно старые файлы Open Access 4 .df в другие форматы, а также создает сценарии базы данных - я уже могу конвертировать все возможные типы, кроме десятичного типа. Я узнал, что порядок байтов должен быть 80-битной расширенной точностью. Я уже пытался выполнить преобразование самостоятельно, но мне не удалось выполнить преобразование из 80-битной расширенной точности (https://en.wikipedia.org/wiki/Extended_precision#x86_Extended_Precision_Format) в String и String в 80-битную расширенную точность в Java.

  1. Пример:

Стоимость: 1235

Hex из файла df: 40 00 9e 06 52 14 1e f0 db f6

  1. Пример:

Стоимость: 0,750

Hex из файла df: 3f ff c0 00 00 00 00 00 00 00

Может кто поможет с переделкой?

С наилучшими пожеланиями

Комментарий @EJP: Хорошо, я отбрасываю последние 16 бит, поэтому я получил 3f ff c0 00 00 00 00 00 относительно (Java - преобразовать шестнадцатеричный код в 64-битный IEEE-754 с плавающей запятой - двойная точность) Я пытаюсь преобразовать его с помощью

String hex = "3fffc00000000000";
long longBits = Long.valueOf(hex ,16).longValue();
double doubleValue = Double.longBitsToDouble(longBits);

Но результат 1,984375 а не 0,750


person daTake    schedule 27.02.2016    source источник
comment
Я не знаю, что означает «бинарная строка», но все, что вам нужно сделать, это отбросить последние 16 бит и преобразовать остальные в double. Не сложно, и все это выполнимо в JDK API.   -  person user207421    schedule 27.02.2016
comment
@ Жан-Франсуа Савар - Long.valueOf(hex,16) принимает шестнадцатеричный код в качестве входных данных;) поэтому Long.valueOf(hex,16) и Long#decode дают одинаковый результат.   -  person daTake    schedule 27.02.2016
comment
@EJP, вы не можете просто выбросить последние 16 бит, потому что формат другой. Экспонента составляет 15 бит в одном и 11 бит в другом.   -  person Sergei Tachenov    schedule 27.02.2016
comment
Просто выбрасывать 16-битную версию не очень хорошая идея - глядя на эту тему stackoverflow.com/questions/2963055/ есть еще что сделать   -  person daTake    schedule 27.02.2016
comment
знаешь библиотеку? вопрос становится не по теме, я предлагаю вам редактировать в форме. Вы можете попросить помощи у ответчика, если вы не знаете, как   -  person Petter Friberg    schedule 28.02.2016


Ответы (1)


Я не уверен, можно ли это считать ответом или вообще можно ответить, потому что... Вы уверены, что это стандартный 80-битный формат с плавающей запятой? Потому что в таком виде это выглядит немного странно. Возьмите свой первый пример:

40 00 9e...

Здесь 0x4000−16383=1 — показатель степени. Мантисса начинается со старшего бита 1, что соответствует целой части, поэтому она должна иметь форму 1,... x 2^1, что больше 2. Но вы говорите, что она должна быть 1235. Не имеет смысла.

Я создал этот уродливый хак на Java, который как бы собирает двойника:

long high = 0x40_00L;
long low = 0x9e_06_52_14_1e_f0_db_f6L;
long e = (((high & 0x7FFFL) - 16383) + 1023) & 0x7FFL;
long ld = ((high & 0x8000L) << 48)
          | (e << 52)
          | ((low >>> 11) & 0xF_FFFF_FFFF_FFFFL);
System.out.printf("%16X\n", ld);
double d = Double.longBitsToDouble(ld);
System.out.println(d);

Предполагая, что ввод является правильным 80-битным значением, этот фрагмент должен работать нормально, за исключением того, что он не округляется должным образом, не проверяет переполнение, не обрабатывает ненормализованные значения и, вероятно, не может обрабатывать специальные значения, такие как NaN. Для этого ввода он печатает

4003C0CA4283DE1B
2.46913578

Не 1235! Затем я использовал этот код C++ (скомпилированный с помощью GCC, где long double в 80-битном формате):

#include <stdio.h>

int main() {
    long long high = 0x4000;
    long long low = 0x9e0652141ef0dbf6;
    long double d;
    char *pd = (char*)&d, *ph = (char*)&high, *pl = (char*)&low;
    for (int i = 0; i < 8; ++i) {
        pd[i] = pl[i];
    }
    for (int i = 0; i < 2; ++i) {
        pd[8 + i] = ph[i];
    }
    printf("%lf\n", (double) d);
}

Он также печатает 2,469136.

person Sergei Tachenov    schedule 27.02.2016
comment
OP может быть из локали, которая использует запятую в качестве десятичного разделителя... - person Alnitak; 27.02.2016
comment
Здравствуйте, спасибо за ответ - попробовал ваш уродливый хак с некоторыми значениями и да ... ваш результат, разделенный на 2, является точным значением ... - person daTake; 27.02.2016
comment
@Alnitak, я тоже из региона, где используется запятая, хотя лично я предпочитаю точку. Но какое это имеет отношение к примеру? Это на порядок 2, а не на порядок тысяч. Неважно, какой регион, один балл, умноженный на два, не может быть 1235. Тот факт, что он выключен на 2, означает, что либо формат неправильный, либо преобразование неправильное. А так как С++ печатает 2.46..., это означает, что формат неверен. - person Sergei Tachenov; 27.02.2016
comment
@Sergey Tachenov У меня есть конвертер, декомпилированный с помощью ida - я проверю значения - может быть, вы правы - НО возможно, что компания, разработавшая Open Access 4, запутывает значения файла .df. Там нет информации, описывающей метаинформацию в этом файле df и т. Д. - person daTake; 27.02.2016
comment
@Сергей, спасибо, ваш грязный хак работает - да, вы правы, формат не совсем правильный - но, как я уже сказал, каждое число (около 500 тысяч чисел), деленное на два, округленное на HALF_UP на 3 цифры, правильно. - person daTake; 27.02.2016
comment
@daTake, обратите внимание, что я испортил бит знака (использовал неправильную маску для его извлечения). Исправлено это сейчас. - person Sergei Tachenov; 27.02.2016
comment
@Sergey Tachenov вопрос сейчас приостановлен как оффтоп - я не понимаю, что мне делать - вы можете мне помочь? - person daTake; 28.02.2016
comment
@daTake, я точно не знаю. Конечно, вопросы типа «рекомендовать библиотеку» здесь не по теме, поэтому вам следует отредактировать его, чтобы сделать больше. Возможно, удалите эту вещь с библиотекой, вместо этого сделайте «Я пробовал это, но это не работает, кто-нибудь знает надежный способ сделать это?» тип вопроса. - person Sergei Tachenov; 29.02.2016