Непонятное преобразование типов - 2 байта к двойному - PullRequest
0 голосов
/ 08 октября 2009

Недавно меня попросили взять на себя управление проектом, в котором данные формы сигнала отбираются из силового преобразователя и отправляются интеллектуальному агенту, где выполняются вычисления и на основании результатов предпринимаются соответствующие действия.

Следующий (java) фрагмент - это то, что предыдущий кодер использовал для преобразования байтового массива в массив значений типа double:

        LSB = (0XFF & (int)ipPacket[index]);
        double temp = LSB/256.0;

        MSB = (byte)(0XFF & (byte)ipPacket[index+1]);
        double output = (double)(MSB + temp);

        ConvCurrentPhaseR[doubleArrayIndex] = (double)(output);

(Примечание: LSB - это целое число, а MSB - это байт)

Я, честно говоря, понятия не имею, как предыдущий кодер придумал это преобразование. Это не имеет никакого смысла для меня. Зачем делить LSB на 256? Даже если исходные данные являются числами с плавающей запятой (4 байта), как мы получаем удвоение (8 байтов) только из 2 байтов? Может ли кто-нибудь объяснить, что происходит с этим фрагментом кода?

Заранее благодарим за любую помощь!

Ответы [ 5 ]

1 голос
/ 09 октября 2009

Вот мое предположение о драке ... в некоторых случаях повторение или консолидация того, что говорили другие, но в контексте.

Исходные данные имеют формат 16 бит с фиксированной запятой. Это имеет меньший диапазон, чем float или double, но имеет большую точность, чем 16-битная плавающая точка. Здесь 8 битов со знаком задаются для целой части числа, а 8 бит - для десятичной части.

Для тех, кто не знаком с представлением с фиксированной запятой, это похоже на сохранение денежных значений в виде целых «центов» при делении на 100 для отображения «долларов».

    LSB = (0XFF & (int)ipPacket[index]);
    double temp = LSB/256.0;

В приведенном выше примере первый байт превращается в десятичную часть значения с использованием деления с плавающей запятой. LSB / 256.0 выдаст двойное значение между 0,0 и 0,99609375.

    MSB = (byte)(0XFF & (byte)ipPacket[index+1]);

Предполагается, что приведенный выше код нормализует второй байт. Если ipPacket является массивом byte [], то это ничего не делает, так как бит знака уже в порядке. ipPacket [index + 1] уже был бы между -128 и 127. Код имеет смысл, только если ipPacket - это не байтовый массив, и даже в этом случае он немного переусердствовал в своем приведении, так как & 0XFF будет повышать значение до в любом случае целое число ... прямо перед преобразованием его обратно в байт.

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

Если ipPacket является массивом byte [], тогда:

MSB = ipPacket[index+1];

Должно быть в порядке. Если ipPacket не является массивом byte [], тогда все равно должно быть достаточно:

MSB = (byte)(0xFF & ipPacket[index+1]);

Как говорили другие, этот последний бит затем объединяет целые числа и десятичные части:

    double output = (double)(MSB + temp);
    ConvCurrentPhaseR[doubleArrayIndex] = (double)(output);

Хотя важно отметить, что десятичная часть добавляется к целой числовой части. Это означает, что MSB = -1 и LSB = 128 приведут к -0,5, а не к -1,5, как можно было изначально ожидать.

1 голос
/ 08 октября 2009

Из быстрого прочтения мне кажется, что результат такой же, как:

output = (double)(ipPacket[index + 1] + (ipPacket[index] / 256.0));

Предполагается, что ipPacket является байтовым массивом, а (0xFF & byte) == байт. Он эффективно хранит десятичную часть двойного в ipPacket[index] как кратное 1/256 и целую часть в ipPacket[index+1].

У него гораздо меньший диапазон, чем у обычного двойника, что может быть тем, что вы путаете.

Эффективный диапазон значений, при условии байтов без знака, является двойным от 0 до 255.99609375 с ограниченным диапазоном представленных десятичных значений.

Редактировать: Значение 256 не включает в себя, так как байт без знака будет в диапазоне 0-255, десятичная область будет в диапазоне 0 - (255/256 == .99609375)

0 голосов
/ 08 октября 2009

Примечание к ответу гвардии:

(0xFF & byte) == byte

Это не так для Java, вы должны добавить бит знака в результирующее значение типа int или float. Оригинальный код:

(0XFF & (int)ipPacket[index]);

удаляет знаковый бит, а:

(byte)(0XFF & (byte)ipPacket[index+1]);

явно хранит его, чтобы он был включен в результирующее число с плавающей точкой. Итоговое значение конверсии будет от -127 до 127 плюс от 0 до 255 / 256.

0 голосов
/ 08 октября 2009

Я предполагаю, что первый байт содержит часть после десятичной точки как "x / 256", а второй байт содержит часть перед десятичной точкой.

Таким образом, для 4.5, первый байт будет 128 (128/256 = 1/2 = 0,5), второй байт будет 4, и в результате получим два сложенных вместе.

0 голосов
/ 08 октября 2009

Ключ не в том, что он делит на 256, а на 256.0. Арифметическая операция с целочисленным операндом и операндом double / float даст результат double / float. Если бы оба операнда были целыми числами, то результатом было бы целое число.

...