int를 두 개의 반바지(.NET)로 나누는 좋은 방법이 있습니까?
저는 이것이 가능하지 않다고 생각합니다 왜냐하면Int32
에는 1비트 부호가 있고 31비트의 숫자 정보가 있으며 Int16에는 1비트 부호와 15비트의 숫자 정보가 있으며, 이로 인해 2비트 부호와 30비트의 정보가 있습니다.
이것이 사실이라면 나는 가질 수 없습니다.Int32
동강으로Int16
이것이 사실입니까?
잘 부탁드립니다.
추가 정보:Vb 사용.네, 하지만 C# 답변은 문제 없이 번역할 수 있을 것 같습니다.
처음에 제가 하고 싶었던 것은 하나를 변환하는 것이었습니다.UInt32
십중팔구UInt16
이것은 WORD 기반 기계와 상호 작용하는 라이브러리를 위한 것입니다. 때 저는 그깨달요어았때요▁that어았달▁realized▁then.Uint
CLS와 을 수행하려고 .Int32
그리고.Int16
.
나쁜 것 더 나쁜 것: 하기.a = CType(c And &HFFFF, Int16);
OverflowException
나는 그 진술이 다음과 같을 것이라고 예상했습니다.a = (Int16)(c & 0xffff);
(예외를 던지지 않음).
이것은 확실히 정보의 손실 없이 수행될 수 있습니다.두 경우 모두 32비트의 정보를 얻을 수 있습니다.부호 비트에 사용되는지 여부는 관련이 없습니다.
int original = ...;
short firstHalf = (short) (original >> 16);
short secondHalf = (short) (original & 0xffff);
int reconstituted = (firstHalf << 16) | (secondHalf & 0xffff);
여기서,reconstituted
항상같과 같음original
따라서 정보가 손실되지 않습니다.
이제 두 반바지의 기호의 의미는 다른 문제입니다.firstHalf
만약 그렇다면 음이 될 것입니다.original
부적이만지정,▁is부적만.secondHalf
의 비 (0-31)의 비트 음 우 이 됩 니 다 경 counting 트이면 음이 .original
설정되어 있습니다. 이는 원래 형식에서 특별히 의미가 없습니다.
이렇게 하면 됩니다.
int original = ...;
byte[] bytes = BitConverter.GetBytes(original);
short firstHalf = BitConverter.ToInt16(bytes, 0);
short secondHalf = BitConverter.ToInt16(bytes, 2);
편집:
0x7FFFF로 테스트, 작동합니다.
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);
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을 제공합니다(오버플로 없음).이는 기본적으로 C# 컴파일러가 선택되지 않은 작업을 사용하고 VB.NET이 선택되었기 때문입니다.
개인적으로 저는 Agg의 답변을 좋아합니다. 왜냐하면 제 코드는 더 복잡하고 Jon의 코드는 확인된 환경에서 오버플로 예외를 일으킬 수 있기 때문입니다.
저는 또한 다음의 코드를 기반으로 다른 답변을 만들었습니다.BitConverter
클래스, 이 특정 작업에 최적화되었습니다.그러나 안전하지 않은 코드를 사용합니다.
네, 마스킹과 비트 시프트를 사용하여 수행할 수 있습니다.
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(안드)여야만 했어요.
왜 안 되나요?단순성을 위해 비트 수를 줄입니다. 왼쪽 비트가 마이너스 비트인 8비트가 있다고 가정해 보겠습니다.
[1001 0110] // representing -22
2 곱하기 4 비트로 저장할 수 있습니다.
[1001] [0110] // representing -1 and 6
나는 왜 그것이 가능하지 않은지 모르겠다, 당신은 8비트 정보를 두 번 가지고 있습니다.
편집: 단순성을 위해 비트를 줄였을 뿐만 아니라 2-보충 방법을 사용하지 않습니다.내 예에서 왼쪽 비트는 마이너스를 나타내고, 나머지는 정상 양의 이진수로 해석됩니다.
C#의 안전하지 않은 코드, 오버플로가 발생하지 않으며 엔디언을 자동으로 감지합니다.
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])
};
}
}
}
VB.NET에서 Struct Layout을 사용할 수 있습니다.
수정: 단어는 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
편집:
답변을 몇 번이나 급히 올리거나 편집했지만 아직 이 솔루션에 대해 설명하지 못해서 답변을 완료하지 못한 것 같습니다.이제부터 그렇게 하겠습니다.
StructureLayout을 구조물에 명시적으로 사용하려면 FieldOffset 속성 [FieldOffsetAttribute]을 사용하여 각 필드의 위치(바이트 오프셋 기준)를 지정해야 합니다.
이 두 가지 속성을 사용하여 겹치는 필드(유니온)를 만들 수 있습니다.
첫 번째 필드(DWord).값)은 오프셋이 0인 32비트 정수입니다.이 32비트 정수를 분할하려면 오프셋 0(0)에서 다시 시작하는 두 개의 추가 필드가 있고 16비트(짧은) 정수는 1개당 2바이트이므로 두 번째 필드는 2바이트 더 꺼집니다.
제가 기억하는 바로는, 보통 정수를 나눌 때, 그들은 일반적으로 첫 번째 절반을 "높음"이라고 부르고, 두 번째 절반을 "낮음"이라고 부릅니다. 그래서 저의 다른 두 개의 필드에 이름을 붙입니다.
이와 같은 구조를 사용하면 연산자에 대한 오버로드를 생성하고 너비/좁게 입력하여 Int32 유형에서 이 DWord 구조로 쉽게 교환할 수 있을 뿐만 아니라 VB.NET의 연산자 오버로드도 비교할 수 있습니다.
Struct Layout을 사용하여 다음 작업을 수행할 수 있습니다.
[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};
저장소 너비(32비트 및 16비트)로 인해 Int32를 Int16으로 변환하면 Int32가 32767보다 클 경우 정보가 손실될 수 있습니다.
만약 당신이 비트 표현을 본다면, 당신이 맞습니다.
서명되지 않은 int를 사용하면 이 작업을 수행할 수 있습니다. 서명된 int에는 기호 비트가 없기 때문입니다.
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
}
비트 연산자를 사용하지 않았지만 부호 없는 값의 경우 다음과 같이 작동할 수 있습니다.
public (ushort, ushort) SplitToUnsignedShorts(uint value)
{
ushort v1 = (ushort) (value / 0x10000);
ushort v2 = (ushort) (value % 0x10000);
return (v1, v2);
}
또는 표현식 본문 버전:
public (ushort, ushort) SplitToUShorts(uint value)
=> ((ushort)(value / 0x10000), (ushort)(value % 0x10000));
기호의 경우, 데이터를 분할할 방법을 결정해야 합니다.음의 출력은 2개 중 1개만 있을 수 있습니다.부호 있는 값은 항상 숫자의 음수 상태를 저장하기 위해 1비트를 희생합니다.그리고 그것은 본질적으로 그 변수에서 가질 수 있는 최대 값을 '반으로' 만듭니다.이것이 또한 uint가 서명된 int보다 두 배 더 많은 양을 저장할 수 있는 이유입니다.
대상 형식으로 인코딩하는 경우 숫자 값을 보존하기 위해 두 번째 숫자를 부호 없는 짧은 숫자로 만들기를 선택하거나 1비트가 해당 값의 기호를 나타내도록 수동으로 인코딩할 수 있습니다.이렇게 하면 기호 비트에 대해 원래 의도한 숫자 값이 손실되더라도 원래 이진 데이터는 손실되지 않으며 항상 원래 값으로 재구성할 수 있습니다.
결국 데이터를 어떻게 저장하고 처리할 것인지에 따라 결정됩니다.인코딩된 값에서 데이터를 추출(또는 병합)하는 방법을 알고 있는 한 비트, 나아가 데이터를 잃지 않습니다.
이 Nuget 패키지 LSharpCode를 사용할 수 있습니다.XExtensions 설치한 후 다음과 같은 방식으로 사용할 수 있습니다.
using LSharpCode.XExtensions.MathExtensions;
Int32 varInt32name;
Int16 varint16nameLow;
Int16 varint16nameHigh;
varInt32name.ToTwoInt16(out varint16nameLow,out varint16nameHigh);
언급URL : https://stackoverflow.com/questions/1873402/is-there-a-nice-way-to-split-an-int-into-two-shorts-net
'programing' 카테고리의 다른 글
따옴표를 자동으로 닫는 성가신 일식 (0) | 2023.05.24 |
---|---|
'WinMain@16'에 대한 정의되지 않은 참조 (0) | 2023.05.24 |
"Please Wait, Loading..."을 생성하려면 어떻게 해야 합니까?jQuery를 사용한 애니메이션? (0) | 2023.05.14 |
아이폰 시뮬레이터에서 키보드를 사용하여 타이핑하려면 어떻게 해야 합니까? (0) | 2023.05.14 |
OpenXML 스프레드시트의 셀 스타일(스프레드시트)ML) (0) | 2023.05.14 |