Подтвердить что ты не робот

Есть ли хороший способ разделить int на два коротких (.NET)?

Я думаю, что это невозможно, потому что Int32 имеет 1 битовый знак и имеет 31 бит числовой информации, а Int16 имеет 1 бит и 15 бит числовой информации, что приводит к наличию 2-битных знаков и 30 бит информации.

Если это правда, я не могу иметь один Int32 на два Int16. Это правда?

Спасибо заранее.

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ: Использование Vb.Net, но я думаю, что я могу без проблем переводить ответ С#.

Вначале я хотел было преобразовать один UInt32 в два UInt16, поскольку это для библиотеки, которая взаимодействует с машинами на основе WORD. Тогда я понял, что Uint не совместим с CLS и пытается сделать то же самое с Int32 и Int16.

ДАЖЕ ИСКУССТВО: Выполнение a = CType(c And &HFFFF, Int16); throws OverflowException. Я ожидал, что оператор будет таким же, как a = (Int16)(c & 0xffff); (который не генерирует исключение).

4b9b3361

Ответ 1

Это должно работать:

int original = ...;
byte[] bytes = BitConverter.GetBytes(original);
short firstHalf = BitConverter.ToInt16(bytes, 0);
short secondHalf = BitConverter.ToInt16(bytes, 2);

EDIT:

тестируется с помощью 0x7FFFFFFF, он работает

byte[] recbytes = new byte[4];
recbytes[0] = BitConverter.GetBytes(firstHalf)[0];
recbytes[1] = BitConverter.GetBytes(firstHalf)[1];
recbytes[2] = BitConverter.GetBytes(secondHalf)[0];
recbytes[3] = BitConverter.GetBytes(secondHalf)[1];
int reconstituted = BitConverter.ToInt32(recbytes, 0);

Ответ 2

Это можно сделать без потери информации. В обоих случаях вы получаете 32 бита информации. Используются ли они для знаковых бит или нет, это не имеет значения:

int original = ...;

short firstHalf = (short) (original >> 16);
short secondHalf = (short) (original & 0xffff);

int reconstituted = (firstHalf << 16) | (secondHalf & 0xffff);

Здесь reconstituted всегда будет равным original, поэтому никакая информация не будет потеряна.

Теперь значение знаков двух шорт - это другое дело - firstHalf будет отрицательным, если if original отрицательно, но secondHalf будет отрицательным, если бит 15 (считая 0-31) of original, что не имеет особого значения в исходной форме.

Ответ 3

Ответить Jon, переведенный на Visual Basic и без переполнения:

Module Module1
    Function MakeSigned(ByVal x As UInt16) As Int16
        Dim juniorBits As Int16 = CType(x And &H7FFF, Int16)
        If x > Int16.MaxValue Then
            Return juniorBits + Int16.MinValue
        End If
        Return juniorBits
    End Function

    Sub Main()
        Dim original As Int32 = &H7FFFFFFF    
        Dim firstHalfUnsigned As UInt16 = CType(original >> 16, UInt16)
        Dim secondHalfUnsigned As UInt16 = CType(original And &HFFFF, UInt16)
        Dim firstHalfSigned As Int16 = MakeSigned(firstHalfUnsigned)
        Dim secondHalfSigned As Int16 = MakeSigned(secondHalfUnsigned)

        Console.WriteLine(firstHalfUnsigned)
        Console.WriteLine(secondHalfUnsigned)
        Console.WriteLine(firstHalfSigned)
        Console.WriteLine(secondHalfSigned)
    End Sub
End Module

Результаты:

32767
65535
32767
-1

В .NET CType(&Hffff, Int16) происходит переполнение, а (short)0xffff - -1 (без переполнения). Это связано с тем, что по умолчанию компилятор С# использует непроверенные операции и проверяет VB.NET.

Лично мне нравится Agg answer, потому что мой код более сложный, и Джон вызывает исключение переполнения в проверенной среде. p >

Я также создал другой ответ на основе кода класса BitConverter, оптимизированного для этой конкретной задачи. Однако он использует небезопасный код.

Ответ 4

да, это может быть сделано с помощью маскировки и битовых сдвигов

 Int16 a,b;
 Int32 c;

 a = (Int16) (c&0xffff);
 b = (Int16) ((c>>16)&0xffff);

ИЗМЕНИТЬ

чтобы ответить на комментарий. Реконструкция прекрасна:

 Int16 a, b;
 Int32 c = -1;

 a = (Int16)(c & 0xffff);
 b = (Int16)((c >> 16) & 0xffff);

 Int32 reconst = (((Int32)a)&0xffff) | ((Int32)b << 16);

 Console.WriteLine("reconst = " + reconst);

Протестировано, и он печатает -1, как ожидалось.

EDIT2: изменил реконструкцию. Продвижение Int16 в Int32 привело к расширению всех битов знака. Забыл, что это должно быть AND'ed.

Ответ 5

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

[1001 0110] // representing -22

Вы можете сохранить его в 2 раза 4 бита

[1001] [0110] // representing   -1 and 6

Я не понимаю, почему это было бы невозможно, у вас дважды есть 8 бит информации

EDIT: Для простоты я не просто уменьшил бит, но также не использовал метод 2-комплемента. В моих примерах левый бит обозначает минус, остальное должно интерпретироваться как нормальное положительное двоичное число

Ответ 6

Вы можете использовать StructLayout в VB.NET:

коррекция: слово 16 бит, dword - 32 бит

<StructLayout(LayoutKind.Explicit, Size:=4)> _
   Public Structure UDWord
      <FieldOffset(0)> Public Value As UInt32
      <FieldOffset(0)> Public High As UInt16
      <FieldOffset(2)> Public Low As UInt16

      Public Sub New(ByVal value As UInt32)
         Me.Value = value
      End Sub

      Public Sub New(ByVal high as UInt16, ByVal low as UInt16)
         Me.High = high
         Me.Low = low
      End Sub
   End Structure

Подписанный будет таким же, просто используя эти типы вместо

<StructLayout(LayoutKind.Explicit, Size:=4)> _
   Public Structure DWord
      <FieldOffset(0)> Public Value As Int32
      <FieldOffset(0)> Public High As Int16
      <FieldOffset(2)> Public Low As Int16

      Public Sub New(ByVal value As Int32)
         Me.Value = value
      End Sub

      Public Sub New(ByVal high as Int16, ByVal low as Int16)
         Me.High = high
         Me.Low = low
      End Sub
   End Structure

EDIT:

Я как бы бросился несколько раз, когда я опубликовал/отредактировал мой андерсер, и все же объяснить это решение, поэтому я чувствую, что не получил ответа. Поэтому я собираюсь сделать это сейчас:

Использование StructLayout как явного в структуре требует, чтобы вы обеспечивали позиционирование каждого поля (по смещению байтов) [StructLayoutAttribute] с атрибутом FieldOffset [Полевой_файл_файла]

Используя эти два атрибута, вы можете создавать перекрывающиеся поля, aka union.

Первое поле (DWord.Value) будет 32-битным целым числом со смещением 0 (ноль). Чтобы разбить это 32-битное целое число, у вас будет два дополнительных поля, начинающихся снова со смещением 0 (ноль), а затем второе поле еще 2 байта, так как 16-битное (короткое) целое число равно 2 байтам a-peice.

Из того, что я помню, обычно, когда вы разделяете целое число, обычно они называют первую половину "высокой", а вторую половину "низкой"; тем самым называя мои два других поля.

Используя такую ​​структуру, вы могли бы создать перегрузки для операторов и тип расширения/сужения, чтобы легко обмениваться с типа Int32 на эту структуру DWord, а также сравнивать Перегрузка оператора в VB.NET

Ответ 7

Небезопасный код в С#, переполнение не происходит, автоматически обнаруживает утверждение:

using System;
class Program
{
    static void Main(String[] args)
    {
        checked // Yes, it works without overflow!
        {
            Int32 original = Int32.MaxValue;
            Int16[] result = GetShorts(original);
            Console.WriteLine("Original int: {0:x}", original);
            Console.WriteLine("Senior Int16: {0:x}", result[1]);
            Console.WriteLine("Junior Int16: {0:x}", result[0]);
            Console.ReadKey();
        }
    }
    static unsafe Int16[] GetShorts(Int32 value)
    {
        byte[] buffer = new byte[4];
        fixed (byte* numRef = buffer)
        {
            *((Int32*)numRef) = value;
            if (BitConverter.IsLittleEndian)
                return new Int16[] { *((Int16*)numRef), *((Int16*)numRef + 1) };
            return new Int16[] { 
                (Int16)((numRef[0] << 8) | numRef[1]),  
                (Int16)((numRef[2] << 8) | numRef[3])
            };
        }
    }
}

Ответ 8

Вы можете использовать StructLayout для этого:

[StructLayout(LayoutKind.Explicit)]
        struct Helper
        {
            [FieldOffset(0)]
            public int Value;
            [FieldOffset(0)]
            public short Low;
            [FieldOffset(2)]
            public short High;
        }

Используя это, вы можете получить полное значение как int, а нижняя часть - как короткая.

что-то вроде:

var helper = new Helper {value = 12345};

Ответ 9

Из-за ширины хранения (32 бит и 16 бит) преобразование Int32 в Int16 может означать потерю информации, если ваш Int32 больше 32767.

Ответ 10

Если вы посмотрите на представление битов, то вы правы.

Вы можете сделать это с помощью unsigned ints, хотя они не имеют знакового бита.

Ответ 11

Вы также можете быть заинтересованы в StructLayout или союзах, если вы используете С++.

Ответ 12

Int32 num = 70000;

        string str = Convert.ToString(num, 2);
    //convert INT32 to Binary string   
        Int32 strl = str.Length;
    //detect string length


        string strhi, strlo;
    //ifvalue is greater than 16 bit 
        if (strl > 16)
        {
           int lg = strl - 16;
          //dtect bits in higher word 
           strlo = str.Substring(lg, 16);
     ///move lower word string to strlo 

            strhi = str.Substring(0, lg);
   //mov higher word string to strhi

        }
        else
//if value is less than 16 bit
        {
           strhi = "0";
//set higher word zero
           strlo = str;
///move lower word string to strlo 

        }

        Int16 lowword, hiword;
        lowword = Convert.ToInt16(strlo, 2);
        hiword = Convert.ToInt16(strhi, 2);
        ////convert binary string to int16
        }