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

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

  1. Пример:

Значение: 1235

Hex from df Файл: 40 00 9e 06 52 14 1e f0 db f6

  1. Пример:

Значение: 0,750

Hex from df File: 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

1 ответ

Решение

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

40 00 9е...

Здесь 0x4000−16383=1 - показатель степени. Мантисса начинается с MSB 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.

Другие вопросы по тегам