Есть ли хороший способ разделить 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);
(который не генерирует исключение).
Ответы
Ответ 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
}