Знак, простирающийся от постоянной битовой ширины в C#

У меня есть значение длиной 5 бит. 4 бита определяют число, а 5-й бит определяет знак, сохраняя любое значение от -16 до +15. Как я могу выполнить расширение знака от постоянной битовой ширины в С#? Я знаю, что в C я могу использовать что-то вроде следующего, чтобы выполнить это:

int x; // convert this from using 5 bits to a full int
int r; // resulting sign extended number goes here
struct {signed int x:5;} s;
r = s.x = x;

Как я могу сделать что-то подобное на С#?


person Icemanind    schedule 20.10.2010    source источник
comment
Извините, я не буду отвечать на ваш вопрос, но я не знал, что вы можете сделать это в C! Можете ли вы создавать переменные произвольной длины в битах? Где я могу найти больше информации об этом?   -  person slezica    schedule 20.10.2010
comment
ха-ха Посмотрите на этот сайт: graphics.stanford.edu/~seander/bithacks.html   -  person Icemanind    schedule 20.10.2010


Ответы (5)


Не совсем понятно, что вы имеете в виду, но это может быть таким простым, как:

int fiveBits = normal & 0x1f;

и для обратного:

int normal =  fiveBits < 16 ? fiveBits : fiveBits | -32;

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

person Jon Skeet    schedule 20.10.2010
comment
Привет, Джон. Проще говоря, у меня есть значение, которое содержится в сбайте. Этот сбайт по определению имеет длину 8 бит. Меня интересуют только первые 5 бит. Значение, которое я пытаюсь извлечь из этих 5 бит, на самом деле представляет собой кусок (4 бита) по длине, таким образом, удерживая значение от 0 до 15. Укус 5 определяет знак (что делает мой возможный диапазон значений от -16 до +15). Итак, например, если мое значение sbyte равно 10 (01010 двоичное), то мой результат должен быть 10. Если мое значение sbyte равно 26 (11010 двоичный), тогда мой результат должен быть -6 (потому что мой 5-й бит равен 1 или подписан). Имеет ли это смысл? - person Icemanind; 20.10.2010
comment
@icemanind: Итак, я привел вам пример с использованием int - вы должны иметь возможность просто преобразовать результаты в sbyte в каждом случае. - person Jon Skeet; 20.10.2010
comment
Несколько мелко, но я бы выбрал int normal = (fiveBits & 16) == 0 ? fiveBits : fiveBits | -32;. Сравнение меньше чем на самом деле не гарантирует, что бит 5 (бит знака) установлен. Использование побитовой операции И специально проверяет ТОЛЬКО бит 5. Если бы кто-то подбрасывал множество этих значений, вы могли бы создать структуру FiveBits и реализовать неявное преобразование типа в Int32 и из него. Пример: public static implicit operator int(FiveBits fiveBits) { return (fiveBits.Value & 16) == 0 ? fiveBits.Value : fiveBits.Value | -32; }. Это обеспечит безопасность типов и предотвратит ошибки преобразования. Весело! - person Kevin P. Rice; 29.03.2012

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

C# не поддерживает пользовательскую разрядность, но поддерживает бинарные операции и геттеры/сеттеры, что упрощает добавление уровня совместимости. Например, если вы хотите хранить необработанные данные в байте _num, но хотите иметь возможность взаимодействовать с ними, используя стандартный sbyte C#, вы можете использовать следующее:

byte _num;
sbyte num {
    get
    {
        return (sbyte)(((_num & 0x10) << 3) | (_num & 0x0F));
    }
    set
    {
        _num = (byte)((value & 0x0F) | ((value & 0x80) >> 3));
    }
}

Такая оболочка особенно полезна при работе с низкоуровневыми прошивками или встроенными проектами.

person Phil    schedule 06.06.2012

Я просто пишу функцию C (потому что я действительно не знаю C#), которая будет делать это, используя операции, которые, как я знаю, доступны в C#.

int five_bit_to_signed(int five_bit) {
     int sh = (sizeof(int)*8)-5;
     int x = five_bit << sh; // puts your sign bit in the highest bit.
     return x >> sh;  // since x is signed this is an arithmatic signed shift
}
person nategoose    schedule 20.10.2010
comment
Не sizeof(int)-5, а либо sizeof(int)*8-5, либо, по определению C#, прямо 32-5. - person Eugene Ryabtsev; 16.08.2012

Выполните сдвиг влево, а затем арифметический сдвиг вправо, чтобы переместить бит знака в старшую позицию, а затем обратно. Арифметический сдвиг вправо выполнит расширение знака за вас.

Конечно, это зависит от наличия работающей операции арифметического сдвига. Абстрактный язык C не работает (работает он или нет, зависит от реализации), но большинство реализаций работают. Я не уверен насчет С#, но я думаю, что он есть.

person R.. GitHub STOP HELPING ICE    schedule 20.10.2010

Из вашего вопроса видно, что вы хотите иметь структуру, которую можно легко преобразовать в тип int и из него:

struct FiveBit
{
  public int bits;

  public static implicit operator int(FiveBit f)
  {
    return (f.bits & 0x10) == 0 ? f.bits : f.bits | -32;
  }

  public static implicit operator FiveBit(int r)
  {
    return new FiveBit() { bits = r & 0x1f };
  }
}

А вот пример использования:

class FiveBitTest
{
  static void Main(string[] args)
  {
    FiveBit f = new FiveBit();
    int r; // resulting sign extended number goes here

    f.bits = 0;
    r = f;
    Console.WriteLine("r = {0}, f.bits = 0x{1:X}", r, f.bits);

    f.bits = 0x1f;
    r = f;
    Console.WriteLine("r = {0}, f.bits = 0x{1:X}", r, f.bits);

    r = -2;
    f = r;
    Console.WriteLine("r = {0}, f.bits = 0x{1:X}", r, f.bits);
}

Результат вышеизложенного:

r = 0, f.bits = 0x0
r = -1, f.bits = 0x1F
r = -2, f.bits = 0x1E
person Kevin P. Rice    schedule 29.03.2012