INTELLIGENT WORK FORUMS FOR COMPUTER PROFESSIONALS
Log In
Come Join Us!
Are you a Computer / IT professional? Join TekTips Forums!
 Talk With Other Members
 Be Notified Of Responses
To Your Posts
 Keyword Search
 OneClick Access To Your
Favorite Forums
 Automated Signatures
On Your Posts
 Best Of All, It's Free!
 Students Click Here
*TekTips's functionality depends on members receiving email. By joining you are opting in to receive email.
Posting Guidelines
Promoting, selling, recruiting, coursework and thesis posting is forbidden. Students Click Here

Visual Basic (Microsoft) VB.NET FAQ
Howto
Understanding unsigned integers by Ruffnekk
Posted: 17 Aug 05 (Edited 17 Aug 05)

This FAQ will explain the difference between signed and unsigned integers, the binary explanation of a number and how to convert and work with unsigned integers in Visual Basic .NET. No knowledge of binary numbers, integers or datatypes in general is required. The FAQ is meant for beginners through experienced users, though the more experienced user may skip many basic explanations throughout the FAQ.
When working with databases, CIM/WMI, COM classes, dynamic link libraries, API's and other objects usually created in another language then VB .NET you may encounter a returned value of an unsigned integer type.
VB .NET has very little support for these datatypes, even though there are some structures defined for it: Uint16, Uin32 and Uint64. These are not types, but structures and there are no operators defined for them. In other words, you can't perform calculations on unsigned integers in VB .NET like you would in C/C++ for example. The only unsigned integer truly supported and CLS compliant in VB .NET is the System.Byte structure, which represents an 8bit unsigned integer.
In VB .NET you are used to working with types like Short, Integer, Long, Decimal among others. The Short datatype is a 16bit signed integer, an Integer is as 32bit signed integer and Long is as 64bit signed integer. The decimal is a somewhat special type which I will explain later. The difference between a signed and an unsigned integer is exactly what the name implies: a signed integer uses the left most bit to indicate wether the number represents a positive or negative number (it's sign), where an usigned integer does not.
This in fact means that a 16bit signed integer can use 15 bits to store it's value and 1 bit to indicate it's sign. An unsigned 16bit integer can use all 16 bits to store it's value. The range of these both is the same, but the minimum and maximum values are very different. To understand the implications you should know about the binary format of a number.
The binary number 10000001 may both represent a signed and an unsigned 8bit integer. The value here is different though. To comprehend the difference I will first explain how a binary number is interpreted in both cases.
A binary number represents powers of 2, from right to left:
2^7 2^6 2^5 2^4 2^3 2^2 2^1 2^0 128 64 32 16 8 4 2 1  1 0 0 0 0 0 0 1 = 2^0 + 2^7 = 1 + 128 = 129 (unsigned)
1 0 0 0 0 0 0 1 = 2^0 + (2)^7 = 1  128 = 127 (signed)
As you can see the result from the same binary number differs greatly depending on which datatype is used. As a rule, you use 2^n for the left most bit if it is set (it's value is 1) when working with signed integers. For positive numbers the result will be the same:
2^7 2^6 2^5 2^4 2^3 2^2 2^1 2^0 128 64 32 16 8 4 2 1  0 0 0 0 0 0 0 1 = 2^0 = 1 (unsigned)
0 0 0 0 0 0 0 1 = 2^0 = 1 (signed)
Since the left most bit is not set here, it represents 0 * 2^7 or 0 * (2)^7 which both results in 0.
Now let's look at the largest positive value these 8bit integers can store:
2^7 2^6 2^5 2^4 2^3 2^2 2^1 2^0 128 64 32 16 8 4 2 1  1 1 1 1 1 1 1 1 = 2^0 + ... + 2^7 = 1 + ... + 128 = 255 (unsigned)
0 1 1 1 1 1 1 1 = 2^0 + ... + 2^6 = 1 + ... + 64 = 127 (signed)
Obviously, an unsigned integer can hold a greater positive value than a signed integer, because the left most bit must be set to 0 to indicate it's a positive number.
For negative numbers, the minimum value for an unsigned integer is always 0 since it cannot represent a negative number. So the range of an 8bit unsigned integer is 0 to 255, which are 256 (2^8) different values. Thus, a 16bit unsigned integer can hold 2^16 = 65536 different values, it's range being 0 to 65535.
The minimum value of an 8bit signed integer is:
2^7 2^6 2^5 2^4 2^3 2^2 2^1 2^0 128 64 32 16 8 4 2 1  1 0 0 0 0 0 0 0 = 2^7 = 128
The range of an 8bit signed integer is 128 to 127, which also represents 256 different values. From the above we may conclude that wether the integer is signed or unsigned, it can always hold only 2^n different values, where n represents it's bit length.
Knowing this, you can see the problem when converting from unsigned to signed integers arousing; the unsigned integer may very well have a larger positive value than can be stored in the equivalent signed integer. With equivalent I mean they both use the same number of bits. The problem is solved easily theoritically: use one more bit for the signed datatype so it uses the same number of bits to store it's value. Now, practically, a 9bit signed integer doesn't exist in VB .NET and we have to resort to other options. When converting from unsigned to signed integers you should use the following VB .NET datatypes:
Uint8 > Byte (which already is a predefined, usable 8bit unsigned integer) Uint16 > Integer (32bit signed integer) Uint32 > Long (64bit signed integer) Uint64 > Decimal (96bit signed 'integer', with some special properties)
As a rule, you take the next larger signed datatype in bit length, to ensure the value will 'fit' in the signed target datatype.
Keeping this in mind, you could use the following function in VB .NET to convert a Uint16 to Integer:
CODE Friend Function Uint16ToInteger(ByVal value As UInt16) As Integer Return Integer.Parse(value.ToString) End Function The Integer.Parse method provided by VB .NET parses a string representation of a value and converts it to an integer value. Since the only way to get the numeric value for a Uint16 is using the ToString method, the function first gets this value as a string, and then converts that string to an integer. Since an unsigned 16bit integer can never hold a larger value than an 32bit signed integer can, this is safe to use.
The same applies to all other conversions:
CODE Friend Function Uint32ToLong(ByVal value As UInt32) As Long Return Long.Parse(value.ToString) End Function
Friend Function Uint64ToDecimal(ByVal value As UInt64) As Decimal Return Decimal.Parse(value.ToString) End Function The Decimal structure represents a number that is a signed, fixedpoint value consisting of an integral part and an optional fractional part. The integral part is interesting to us. The Decimal datatype consists of 128bits, of which 96 may be used to store an integer value. Thus we can use it to convert an 64bit unsigned integer, ignoring the fractional part of the decimal (which will be .0 any way).
Using these functions you are left with Integers, Longs and Decimals to perform further calculations. When it comes to converting these values back to unsigned integers, there are some tricky issues to deal with.
Most importantly, converting a negative integer to an unsigned integer may leave you dazzled with the results, although it is very logical. Let's look at an example:
2^7 2^6 2^5 2^4 2^3 2^2 2^1 2^0 128 64 32 16 8 4 2 1  1 0 1 1 0 1 0 1 = 1 + 4 + 16 + 32  128 = 75 (signed)
1 0 1 1 0 1 0 1 = 1 + 4 + 16 + 32 + 128 = 181 (unsigned)
Now this is certainly not what we want, and when you even try this in the above functions, the system will throw an exception telling you the number is too small. Therefore, you should always check to see wether the signed integer you wish to convert is greater than or equal to 0.
I will explain another issue by a practical example:
Let's say you got a value of Uint16 from a database field and converted it to an Integer (32bit signed). After some operations on the Integer value, you want to store it back into the database. You need to convert it back to Uint16 again. The problem here is that the Integer value can actually be larger than what a Uint16 can hold. There's no way around this and you will have to check wether the Integer value isn't too large now to convert it back.
The maximum value of Uint16 is 2^16  1 = 65535. (1 because of zero; 2^16 is the number of different value it can hold). Thus the maximum value of Uint32 is 2^32  1 = 4294967295. The same applies for Uint64.
When you have checked this, you can convert the values to unsigned integers thus:
CODE Friend Function IntegerToUint16(ByVal value As Integer) As Uint16 If value < 2 ^ 16 Then Return Uint16.Parse(value.ToString) Else Throw New OverflowException(value.ToString & " is too large to convert to a 16bit unsigned integer! It must be less than " & (2 ^ 16).ToString & "!") End If End Function You can now easily write similar functions for the other datatypes:
CODE Friend Function LongToUint32(ByVal value As Long) As UInt32 If value < 2 ^ 32 Then Return UInt32.Parse(value.ToString) Else Throw New OverflowException(value.ToString & " is too large to convert to a 32bit unsigned integer! It must be less than " & (2 ^ 32).ToString & "!") End If End Function
Friend Function DecimalToUint64(ByVal value As Decimal) As UInt64 If value < 2 ^ 64 Then Return UInt64.Parse(value.ToString) Else Throw New OverflowException(value.ToString & " is too large to convert to a 64bit unsigned integer! It must be less than " & (2 ^ 64).ToString & "!") End If End Function An option is to convert the large integer to a bigger unsigned integer, but you will most likely encounter the conversion problem further on (in your database for example, when you try to store a Uint32 in a field defined as Uint16).
That's it! Thank you for reading this FAQ and I hope you learned something from it. If you have any comments or corrections, feel free to drop me a message. There's always new things to discover!
Best regards, Ruffnekk 
Back to Visual Basic (Microsoft) VB.NET FAQ Index
Back to Visual Basic (Microsoft) VB.NET Forum 


