Reputation: 21855
I think that this is not possible because Int32
has 1 bit sign and have 31 bit of numeric information and Int16 has 1 bit sign and 15 bit of numeric information and this leads to having 2 bit signs and 30 bits of information.
If this is true then I cannot have one Int32
into two Int16
. Is this true?
Thanks in advance.
EXTRA INFORMATION: Using Vb.Net but I think that I can translate without problems a C# answer.
What initially I wanted to do was to convert one UInt32
to two UInt16
as this is for a library that interacts with WORD based machines. Then I realized that Uint
is not CLS compliant and tried to do the same with Int32
and Int16
.
EVEN WORSE: Doing a = CType(c And &HFFFF, Int16);
throws OverflowException
. I expected that statement being the same as a = (Int16)(c & 0xffff);
(which does not throw an exception).
Upvotes: 35
Views: 22977
Reputation: 637
you can use this Nuget package LSharpCode.XExtensions When you had installed it ,you can use it in this way:
using LSharpCode.XExtensions.MathExtensions;
Int32 varInt32name;
Int16 varint16nameLow;
Int16 varint16nameHigh;
varInt32name.ToTwoInt16(out varint16nameLow,out varint16nameHigh);
Upvotes: 0
Reputation: 595
I did not use bitwise operators but for unsigned values, this may work:
public (ushort, ushort) SplitToUnsignedShorts(uint value)
{
ushort v1 = (ushort) (value / 0x10000);
ushort v2 = (ushort) (value % 0x10000);
return (v1, v2);
}
Or an expression body version of it:
public (ushort, ushort) SplitToUShorts(uint value)
=> ((ushort)(value / 0x10000), (ushort)(value % 0x10000));
As for signs, you have to decide how you want to split the data. There can only be 1 negative output out of two. Remember a signed value always sacrifices one bit to store the negative state of the number. And that essentially 'halves' the maximum value you can have in that variable. This is also why uint can store twice as much as a signed int.
As for encoding it to your target format, you can either choose make the second number an unsigned short, to preserve the numerical value, or you can manually encode it such that the one bit now represent the sign of that value. This way although you will lose the originally intended numeric value for a sign bit, you don't lose the original binary data and you can always reconstruct it to the original value.
In the end it comes down to how you want to store and process that data. You don't lose the bits, and by extension, the data, as long as you know how to extract the data from (or merge to) your encoded values.
Upvotes: 0
Reputation: 1
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
}
Upvotes: 0
Reputation: 3586
Jon's answer, translated into Visual Basic, and without overflow:
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
Results:
32767
65535
32767
-1
In .NET CType(&Hffff, Int16)
causes overflow, and (short)0xffff
gives -1 (without overflow). It is because by default C# compiler uses unchecked operations and VB.NET checked.
Personally I like Agg's answer, because my code is more complicated, and Jon's would cause an overflow exception in checked environment.
I also created another answer, based on code of BitConverter
class, optimized for this particular task. However, it uses unsafe code.
Upvotes: 7
Reputation: 2348
You can use StructLayout to do this:
[StructLayout(LayoutKind.Explicit)]
struct Helper
{
[FieldOffset(0)]
public int Value;
[FieldOffset(0)]
public short Low;
[FieldOffset(2)]
public short High;
}
Using this, you can get the full Value as int , and low part, hight part as short.
something like:
var helper = new Helper {value = 12345};
Upvotes: 2
Reputation: 371
You can use StructLayout in VB.NET:
correction: word is 16bit, dword is 32bit
<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
Signed would be the same just using those types instead
<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:
I've kind of rushed the few times I've posted/edited my anwser, and yet to explain this solution, so I feel I have not completed my answer. So I'm going to do so now:
Using the StructLayout as explicit onto a structure requires you to provide the positioning of each field (by byte offset) [StructLayoutAttribute] with the FieldOffset attribute [FieldOffsetAttribute]
With these two attributes in use you can create overlapping fields, aka unions.
The first field (DWord.Value) would be the 32bit integer, with an offset of 0 (zero). To split this 32bit integer you would have two additional fields starting again at the offset of 0 (zero) then the second field 2 more bytes off, because a 16bit (short) integer is 2 bytes a-peice.
From what I recall, usually when you split an integer they normally call the first half "high" then the second half "low"; thus naming my two other fields.
With using a structure like this, you could then create overloads for operators and type widing/narrowing, to easily exchange from say an Int32 type to this DWord structure, aswell as comparasions Operator Overloading in VB.NET
Upvotes: 2
Reputation: 3586
Unsafe code in C#, overflow doesn't occur, detects endianness automatically:
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])
};
}
}
}
Upvotes: 2
Reputation: 48978
Why not? Lets reduce the number of bits for the sake of simplicity : let's say we have 8 bits of which the left bit is a minus bit.
[1001 0110] // representing -22
You can store it in 2 times 4 bits
[1001] [0110] // representing -1 and 6
I don't see why it wouldn't be possible, you twice have 8 bits info
EDIT : For the sake of simplicity, I didn't just reduce the bits, but also don't use 2-complementmethod. In my examples, the left bit denotes minus, the rest is to be interpreted as a normal positive binary number
Upvotes: 3
Reputation: 15935
yes it can be done using masking and bitshifts
Int16 a,b;
Int32 c;
a = (Int16) (c&0xffff);
b = (Int16) ((c>>16)&0xffff);
EDIT
to answer the comment. Reconstructionworks fine:
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);
Tested it and it prints -1 as expected.
EDIT2: changed the reconstruction. The promotion of the Int16 to Int32 caused all sign bits to extend. Forgot that, it had to be AND'ed.
Upvotes: 4
Reputation: 465
This should work:
int original = ...;
byte[] bytes = BitConverter.GetBytes(original);
short firstHalf = BitConverter.ToInt16(bytes, 0);
short secondHalf = BitConverter.ToInt16(bytes, 2);
EDIT:
tested with 0x7FFFFFFF, it works
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);
Upvotes: 16
Reputation: 1502476
This can certainly be done with no loss of information. In both cases you end up with 32 bits of information. Whether they're used for sign bits or not is irrelevant:
int original = ...;
short firstHalf = (short) (original >> 16);
short secondHalf = (short) (original & 0xffff);
int reconstituted = (firstHalf << 16) | (secondHalf & 0xffff);
Here, reconstituted
will always equal original
, hence no information is lost.
Now the meaning of the signs of the two shorts is a different matter - firstHalf
will be negative iff original
is negative, but secondHalf
will be negative if bit 15 (counting 0-31) of original
is set, which isn't particularly meaningful in the original form.
Upvotes: 41
Reputation: 499172
If you look at the bit representation, then you are correct.
You can do this with unsigned ints though, as they don't have the sign bit.
Upvotes: 0
Reputation: 27899
Due to storage width (32bits and 16bits), converting Int32 to Int16 may imply a loss of information, if your Int32 is greater than 32767.
Upvotes: 0