Арифметическое битовое смещение типа данных с двойной переменной в C - PullRequest
6 голосов
/ 10 августа 2011

Я пытаюсь арифметически сдвинуть бит двойного типа данных в C. Мне было интересно, если это правильный способ сделать это:

ПРИМЕЧАНИЕ: firdelay [] [] объявлен в main как double firdelay[8] [12]

void function1(double firdelay[][12]) {
    int * shiftptr;

    // Cast address of element of 2D matrix (type double) to integer pointer
    *shiftptr = (int *) (&firdelay[0][5]); 

    // Dereference integer pointer and shift right by 12 bits
    *shiftptr >>= 12; 
}

Ответы [ 6 ]

6 голосов
/ 10 августа 2011

Битовое смещение типа данных с плавающей запятой не даст желаемого результата.

В Simulink арифметический блок сдвига выполняет битовое смещение только для целочисленных типов данных.Если вы передаете ему тип с плавающей запятой, он делит входной сигнал на 2^N, где N - это число битов для сдвига, указанное в диалоговом окне маски.

РЕДАКТИРОВАТЬ: Поскольку у вас нет возможности выполнять математику с плавающей запятой, вы можете выбрать следующие варианты:

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

Я бы порекомендовал вариант 2, это намного проще, чем 1

4 голосов
/ 10 августа 2011

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

Если вы хотите умножить / разделить на степень 2, то вам следует сделать это явно.

1 голос
/ 10 августа 2011

Согласно плохо сформулированной и очень неясной документации , кажется, что "сдвиг битов" в Simulink принимает два аргумента для значений с плавающей запятой и приводит к умножению значения с плавающей запятой на два, возведенных вРазница аргументов.

Вы можете использовать ldexp(double_number, bits_to_pseudo_shift), чтобы получить это поведение.Функция ldexp находится в <math.h>.

0 голосов
/ 29 мая 2019

Есть способ достичь этого: просто добавьте n к экспонентной части побитового представления двойного числа.Преобразуйте двойное число в длинное с помощью «переинтерпретации» или побитового преобразования (например, с помощью объединения). Извлеките биты из 52 в 63 (11 бит). Затем добавьте сдвиг и верните результат в экспоненту.Вы должны принять во внимание специальные значения double (+ бесконечность, нан или ноль)

double operator_shift_left(double a,int n)
{
    union 
    {
        long long l;
        double d;
    } r;
    r.d=a;
    switch(r.l)
    {
        case 0x0000000000000000: // 0
        case 0x8000000000000000: // -0
        case 0x7FF0000000000000: // pos infnity
        case 0xFFF0000000000000: // neg infnity
        case 0x7FF0000000000001: // Nan
        case 0x7FF8000000000001: // Nan
        case 0x7FFFFFFFFFFFFFFF: // Nan
            return a;
    }
    int nexp=(((r.l>>52)&0x7FF)+n); // new exponent
    if (nexp<0) // underflow 
    {
        r.l=r.l &  0x8000000000000000;
        // returns +/- 0
        return r.d;
    }
    if (nexp>2047) // overflow
    {
        r.l=(r.l & 0x8000000000000000)| 0x7FF0000000000000;
        // returns +/- infinity
        return r.d;
    }
    // returns the number with the new exponant

    r.l=(r.l & 0x800FFFFFFFFFFFFF)|(((long long)nexp)<<52); 
    return r.d;


}

(вероятно, есть какая-то инструкция процессора x64, которая это делает?)

0 голосов
/ 13 марта 2017

Один из возможных вариантов использования этого - захват битов мантиссы, битов экспоненты и знакового бита, если это необходимо.Для этого вы можете использовать объединение:

union doubleBits {
    double d;
    long l;
};

Вы можете установить дубль и установить его в объединении:

union doubleBits myUnion;
myUnion.d = myDouble;

И сдвинуть бит длинной части объединения после извлечениябиты примерно так:

myUnion.l >>= 1;

Поскольку число битов для каждой части двойного числа определено, это один из способов извлечь базовое представление битов.Это один из случаев использования, когда можно получить необработанные базовые биты.Я не знаком с Simulink, но если, возможно, именно поэтому двойник был смещен в первую очередь, это может быть способом достижения такого поведения в C. Тот факт, что это всегда было 12 бит, заставляет меня думать иначе, нона всякий случай решил, что стоит указать другим, кто наткнулся на этот вопрос.

0 голосов
/ 10 августа 2011

Нет правильного способа сделать это.Оба операнда << должны иметь некоторый целочисленный тип.

То, что вы делаете, интерпретирует ("наказание типа") объект double, как если бы это был объект int, а затемсдвиг результирующего значения int.Даже если double и int имеют одинаковый размер, вряд ли что-то пригодится.(И даже если это полезно, имеет смысл смещать значения без знака, а не значения со знаком).

...