Как преобразовать десять байтов в число с плавающей запятой - PullRequest
0 голосов
/ 11 марта 2019

У меня есть несколько устаревших файлов, которые нужно добывать для данных.Файлы были созданы Lotus123 Release 4 для DOS.Я пытаюсь читать файлы быстрее, анализируя байты, а не используя Lotus для открытия файлов.У меня есть записи значений по 10 байт каждая.

@ AndrewMorton из этого Q указывает на http://www.mettalogic.co.uk/tim/l123/l123r4.html#rec17 Он говорит, что у нас есть длинный двойной GNU, который составляет 10 байтов.

Он также указал на Gnumeric , поскольку они читают файлы WK3, но мне трудно найти соответствующий код.

Dim fileBytes() As Byte = My.Computer.FileSystem.ReadAllBytes(fiPath)
Dim arr(10) As Byte
For ...
    arr(x) = fileBytes(x)
    Debug.Print(Convert.ToInt16(fileBytes(x)))
Next ...

'values to the right
Dim data1 As Byte() = New Byte() {0, 0, 0, 0, 0, 45, 17, 188, 22, 64}    ' Value = 12325165
Dim data2 As Byte() = New Byte() {0, 0, 0, 0, 0, 248, 30, 196, 20, 64}   ' Value = 3213246
Dim data3 As Byte() = New Byte() {209, 92, 167, 145, 150, 202, 219, 205, 0, 64} ' Value = 3.21654
Dim data4 As Byte() = New Byte() {0, 0, 0, 0, 0, 120, 68, 196, 20, 64}   ' Value = 3215646
Dim data5 As Byte() = New Byte() {0, 0, 0, 0, 0, 104, 131, 211, 20, 192} ' Value = -3465434
Dim data6 As Byte() = New Byte() {0, 0, 0, 0, 0, 224, 131, 211, 20, 192} ' Value = -3465464
Dim data7 As Byte() = New Byte() {0, 0, 0, 0, 0, 60, 105, 163, 21, 192}  ' Value = -5354654
Dim data8 As Byte() = New Byte() {0, 0, 0, 0, 128, 82, 74, 135, 24, 192} ' Value = -35465546

Dim data1 As Byte() = New Byte() {0, 0, 0, 0, 0, 0, 0, 128, 255, 191}                  ' Value = -1
Dim data2 As Byte() = New Byte() {205, 204, 204, 204, 204, 204, 204, 204, 251, 191}    ' Value = -0.1
Dim data3 As Byte() = New Byte() {10, 215, 163, 112, 61, 10, 215, 163, 248, 191}       ' Value = -0.01
Dim data4 As Byte() = New Byte() {59, 223, 79, 141, 151, 110, 18, 131, 245, 191}       ' Value = -0.001
Dim data5 As Byte() = New Byte() {44, 101, 25, 226, 88, 23, 183, 209, 241, 191}        ' Value = -0.0001
Dim data6 As Byte() = New Byte() {35, 132, 71, 27, 71, 172, 197, 167, 238, 191}        ' Value = -0.00001
Dim data7 As Byte() = New Byte() {182, 105, 108, 175, 5, 189, 55, 134, 235, 191}       ' Value = -0.000001
Dim data8 As Byte() = New Byte() {0, 0, 0, 0, 0, 0, 0, 128, 255, 63}                   ' Value = 1
Dim data9 As Byte() = New Byte() {205, 204, 204, 204, 204, 204, 204, 204, 251, 63}     ' Value = 0.1
Dim data10 As Byte() = New Byte() {10, 215, 163, 112, 61, 10, 215, 163, 248, 63}       ' Value = 0.01
Dim data11 As Byte() = New Byte() {59, 223, 79, 141, 151, 110, 18, 131, 245, 63}       ' Value = 0.001
Dim data12 As Byte() = New Byte() {44, 101, 25, 226, 88, 23, 183, 209, 241, 63}        ' Value = 0.0001
Dim data13 As Byte() = New Byte() {35, 132, 71, 27, 71, 172, 197, 167, 238, 63}        ' Value = 0.00001
Dim data14 As Byte() = New Byte() {182, 105, 108, 175, 5, 189, 55, 134, 235, 63}       ' Value = 0.000001
Dim data15 As Byte() = New Byte() {188, 66, 122, 229, 213, 148, 191, 214, 231, 63}     ' Value = 0.0000001

Я пытался реализовать это , но это не работает;просто дает значения мусора (я попробовал оба ответа дано).

Как мне преобразовать 10-байтовый длинный двойной GNU в десятичный.Поскольку GNU находится на C, я бы приветствовал код на C, но предпочел бы VB.net.

1 Ответ

1 голос
/ 12 марта 2019
Код

C позволяет создать массив из десяти байтов из десяти десятичных значений, а затем интерпретировать этот массив как long double, если реализация long double вашего компилятора совместима с этим форматом. Следующая программа использует десять десятичных знаков, указанных в командной строке. Очевидно, что было бы просто получить числа откуда-то еще, возможно, из стандартного ввода или из файла.

#include <stdlib.h>
#include <stdio.h>

void
show_longdouble(const unsigned char array[]) {
    long double *ldp = (long double *)array;
    int ix;

    for (ix = 0 ; ix < 10 ; ++ix) {
        printf("%u ", array[ix]);
    }
    printf("=> %Lf\n", *ldp);
}

int
main(int argc, char *argv[])
{
    if (11 == argc) {
        unsigned char vals[16]; /* only use 10, but dimension 16 for alignment */
        int ix;

        for (ix = 0 ; ix < 10 ; ++ix) {
            sscanf(argv[ix+1], "%hhu", &vals[ix]);
        }
        show_longdouble(vals);
    }
    return 0;
}

Запуск этой программы дает:

$ ./gnu-long-double 0 0 0 0 0 45 17 188 22 64
0 0 0 0 0 45 17 188 22 64 => 12325165.000000

$ ./gnu-long-double 0 0 0 0 0 248 30 196 20 64
0 0 0 0 0 248 30 196 20 64 => 3213246.000000

Если вы хотите выполнить преобразование вручную, а не полагаться на встроенный компилятор C printf, то этот формат упоминается в Википедии как «Формат расширенной точности x86» и описывается в https://en.wikipedia.org/wiki/Extended_precision#x86_extended_precision_format

...