преобразование байтового массива в двойной - c - PullRequest
8 голосов
/ 19 августа 2009

Я пытаюсь получить числовое (двойное) значение из байтового массива из 16 элементов следующим образом:

unsigned char input[16];
double output;
...
double a  = input[0];
distance = a;
for (i=1;i<16;i++){
    a = input[i] << 8*i;
    output += a;
}

но это не работает. Кажется, что временная переменная, которая содержит результат сдвига влево, может хранить только 32 бита, потому что после 4 операций сдвига из 8 битов она переполняется.

Я знаю, что могу использовать что-то вроде

a = input[i] * pow(2,8*i);

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

Ответы [ 7 ]

4 голосов
/ 19 августа 2009

Проблема здесь в том, что 32-битные переменные не могут быть сдвинуты более чем в 4 * 8 раз, т. Е. Ваш код работает только для 4 символов.

Что вы можете сделать, так это найти первый значащий символ и использовать закон Хорнера: a n x n + a n-1 n -1 + ... = ((... (a n x + a n-1 ) .x + a n-2 ). x + ...) + a 0 следующим образом:

char coefficients[16] = { 0, 0, ..., 14, 15 };
int exponent=15;
double result = 0.;

for(int exponent = 15; exp >= 0; --exp ) {
   result *= 256.; // instead of <<8.
   result += coefficients[ exponent ];
}
4 голосов
/ 19 августа 2009

Изменить: это не будет работать (см. Комментарий) без чего-то вроде __int128.

a = input[i] << 8*i;

Выражение input[i] переводится в int ( 6.3.1.1 ), что на вашем компьютере 32-битное Чтобы преодолеть эту проблему, левый операнд должен быть 64-битным, как в

a = (1L * input[i]) << 8*i;

или

a = (long long unsigned) input[i] << 8*i;

и помните о порядке байтов

2 голосов
/ 20 августа 2009

Почему бы просто не привести массив к двойному указателю?

unsigned char input[16];

double* pd = (double*)input;

for (int i=0; i<sizeof(input)/sizeof(double); ++i)
    cout << pd[i];

если вам нужно исправить порядковый номер, поверните массив char с помощью STL reverse () перед приведением к двойному массиву.

2 голосов
/ 19 августа 2009

Короче говоря, нет, вы не можете преобразовать последовательность byte s непосредственно в double путем сдвига битов, как показано в примере кода.

byte, целочисленный тип и double, тип с плавающей запятой (т. Е. Не целочисленный тип) не совместимы по битам (т. Е. Вы не можете просто сдвинуть биты к значениям группы байтов в тип с плавающей запятой и ожидать эквивалентного результата.)

1) Предполагая, что байтовый массив является буфером памяти, ссылающимся на целочисленное значение, вы должны иметь возможность преобразовать ваш массив byte в 128-битное целое число посредством сдвига битов, а затем преобразовать полученное целое число в double , Не забывайте, что в зависимости от архитектуры процессора могут возникать проблемы с порядком байтов.

2) Предполагая, что байтовый массив является буфером памяти, который содержит 128-разрядное длинное двойное значение, и при условии, что нет никаких проблем с порядком байтов, вы должны иметь возможность запоминать значение из байтового массива в длинное двойное значение

union doubleOrByte {
    BYTE buffer[16];
    long double val;
} dOrb;
dOrb.val = 3.14159267;
long double newval = 0.0;

memcpy((void*)&newval, (void*)dOrb.buffer, sizeof(dOrb.buffer));
1 голос
/ 19 августа 2009

Вы пытаетесь преобразовать строковое представление числа в действительное число? В этом случае, atof C-стандарта - ваш лучший друг.

1 голос
/ 19 августа 2009

Вы пробовали std :: atof:

http://www.cplusplus.com/reference/clibrary/cstdlib/atof/

0 голосов
/ 19 августа 2009

Хорошо, исходя из приоритета оператора в правой части

a = input[i] << 8*i;

вычисляется до того, как оно конвертируется в удвоение, поэтому вы сдвигаете вход [i] на 8 * i битов, что сохраняет его результат в 32-битной временной переменной и, таким образом, переполняется. Вы можете попробовать следующее:

a = (long long unsigned int)input[i] << 8*i;

Редактировать: Не уверен, какой размер двойника на вашей системе, но на моем это 8 байт, если это так и для вас, вторая половина вашего входного массива никогда не будет будет видно, что сдвиг переполнит даже двойной тип.

...