HomeBrainDump Understanding Numeric Data in VBScript
Understanding Numeric Data in VBScript
VBScript—and programming in general—relies very heavily on numeric data. All computer data is stored and processed in binary (numeric) form. However, this data is not limited solely to binary. To properly understand how VBScript operates, it’s important to fully understand numeric data.
Contributed by Nilpo Rating: / 3 February 26, 2008
The two most common data subtypes in VBScript can be divided into two major categories: numeric and string. Numeric data types are interpreted as their name implies, as numbers. Strings, in most cases, consist of human readable alphanumeric characters.
The numeric types can again be divided into two major categories: fixed width and floating point. Fixed width numbers are whole numbers—positive or negative with no decimal points. Floating point numbers are numbers containing decimals and are representative of fractions.
Examples of fixed width numbers:
-1
0
478
-1063
1 x 1035
Examples of floating point numbers:
-1.025
25.64
-4789.256879
1 x 10-35
On most platforms, VBScript is able to make calculations using very large numbers. This, however, consumes a lot of memory depending upon the size of the numbers. For this reason, the different numeric data types were created to make the process more efficient.
Numeric data subtypes represent different levels of precision in these numbers and also control the precision of the numbers that are the result of VBScript’s calculations. Each data subtype allocates a specific amount of memory for a number. Thus, the precision of some numbers can become limited by the amount of memory available to them. Let’s take a look at the numeric subtypes.
Fixed width numeric subtypes
Type
Precision
Data Range
Byte
1 byte
0-255
Integer
2 bytes
-32,768 to 32,767
Long
4 bytes
-2,147,483,648 to 2,147,483,647
Floating point numeric subtypes
Single
4 bytes
-3.402823E38 to -1.401298E-45 for negative values;
1.401298E-45 to 3.402823E38 for positive values
Double
8 bytes
-1.79769313486232E308 to -4.94065645841247E-324 for negative values;
4.94065645841247E-324 to 1.79769313486232E308 for positive values
As you can see, the precision of each data subtype affects the respective data range dramatically. Let’s try to understand exactly what these precisions are and how they affect those ranges.
VBScript also provides two other special numeric types: Date and Currency. Date is a numeric representation of any valid date and Currency is used to force currency calculations.
Computer processors do not actually understand numbers. They work with bit patterns. Think of a bit as a switch that is either on or off, true or false. These bits are combined as strings, known as patterns, to indicate different values. These values are commonly represented as numbers with 0 being on, or true, and 1 being off, or false.
A bit represents a single, two value quantity like: on or off, true or false, 0 or 1.
Bit patterns, then, are combinations of bits. Here are some examples of patterns that can be constructed.
A single bit has two states: either T or F. (21 possibilities)
Two bits can distinguish between four states: TT, TF, FT, FF (22 possibilities)
Three bits can distinguish between eight states: TTT, TTF, TFT, FTT, FFT, FTF, TFF, FFF. (23 possibilities)
As you can see, a bit pattern’s length is very important. The number of possible values for a bit pattern containing a given width is equal to 2n where n represents the number of bits in the pattern. This range is known as a pattern’s width.
Therefore, a bit pattern containing 10 bits would have a width of 210 or 1024 possibilities.
Computer storage is typically stated in bytes. A byte consists of eight bits. Using the formula above you can see that a byte has 28 or 256 possibilities. Thus, the Byte data type, with a precision of a single byte, has 256 possibilities. That’s why its range is 0-255. Remember that 0 is a state and that the Byte type only uses positive numbers.
Here again, the Integer type has a width of two bytes. (Remember that 2 bytes equals 16 total bits.) That means 216 or 65536 possibilities. Since the Integer type allows both positive and negative numbers, divide that by two—half in each direction. Thus you get 32,768 negative possibilities and 32,758 positive possibilities. The 0 state is considered a positive.
So, the Integer type has 32,768 negative possibilities, 0, and 32,757 positive possibilities greater than 0. In other words, its range is any integer between -32,768 and 32,757 including zero.
The floating point ranges are calculated in the same manner, however, there are bits used for the decimal point, so the ranges seem a bit limited compared to their fixed width counterparts.
Keeping in mind that computers interpret bit patterns, humans on the other hand must use more friendly numbers. Different number systems have been devised to ease interpreting different types of numbers.
By far the most common among these number systems is the decimal system that we use every day. This base-10 system was designed to make mathematical calculations much easier—for the human mind that is. The decimal system is harder for computers.
Computer hardware uses the base-2 binary system. This is because CPUs use transistors to perform logical calculations. A transistor has two states: open and closed. This made the binary system a natural choice.
A number system’s base implies the number of possibilities for each digit in a number. Since the binary system allows only two possibilities, it is much faster for a CPU to use these types of numbers. Let’s take a look at the digit possibilities for common number systems:
Binary system – 0, 1
Octal system – 0, 1, 2, 3, 4, 5, 6, 7
Decimal system – 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
Hexadecimal – 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F
In hexadecimal (base-16) there are sixteen possibilities for each digit. Since they can’t be expressed in single decimal digits, letters are used to represent the values 11 to 15.
Counting in Different Number Systems
Bin
Dec
Hex
Bin
Dec
Hex
Bin
Dec
Hex
0
0
0
1001
8
8
10001
16
10
1
1
1
1010
9
9
10010
17
11
10
2
2
1011
10
A
10011
18
12
11
3
3
1100
11
B
10100
19
13
100
4
4
1101
12
C
10101
20
14
101
5
5
1110
13
D
10110
21
15
110
6
6
1111
14
E
10111
22
16
1000
7
7
10000
15
F
11000
23
17
All number systems increment by one starting at zero. Adding numbers in each system is done identically—increment the furthest right digit by one; if it is already at its maximum, reset it to zero and carry to the next place.
An example in hex would be 4A6FF+1=4A700.
Since numbers inherently represent the same quantities, and the mathematical operations on them are the identical, numbers can be converted from one system to another. Since we’re dealing with computers, let’s take a look at how to convert a bit string (from binary) to both octal and hex.
One Octal digit equals three binary digits:
101
101
011
100
101
000
001
011
5
5
3
4
5
0
1
3
One Hexadecimal digit equals four binary digits:
1011
0101
1100
1010
0000
1011
B
5
C
A
0
B
Now that you have a better understanding of number systems, let’s take a look at how VBScript makes it easier for you to work with them.
Let’s begin by examining the conversion functions that VBScript provides for converting actual numbers between the different number systems. VBScript provides functions for converting numbers (assumed to be in decimal notation) into either Hex or Octal.
Hex(number)
Oct(number)
The Hex function returns a string representing the hexadecimal value of a given number. The number provided may be any valid expression.
MyHex = Hex(5) ' Returns 5.
MyHex = Hex(10) ' Returns A.
MyHex = Hex(459) ' Returns 1CB.
If the number provided is not a valid integer, it will be rounded to the nearest whole number before being converted.
If the expression provided does not evaluate to a Boolean (or some other value) its numeric representation will be used in the conversion.
The Oct function returns a string representing the octal value of a given number. The number argument, again, may be any valid expression.
MyOct = Oct(4) ' Returns 4.
MyOct = Oct(8) ' Returns 10.
MyOct = Oct(459) ' Returns 713.
There are no functions for converting to decimal as this is done automatically for any expression that does not use one of the above functions. Take the following code for example.
MyHex = &h14
MyOct = &o101
WScript.Echo "0x14 = " & MyHex
WScript.Echo "O101 = " & MyOct
You can use special notations to indicate that numbers are in a different base. To distinguish hexadecimal numbers, prepend the number with a “0x”. For octal numbers, simply add a leading 0. Any normal integers are assumed to be in decimal notation.
In VBScript you can use special notations to indicate numbers are of a different base as well. Prepending with a “&h” indicates a hexadecimal number while a “&o” indicates an octal number.
So you can see in our code example that we’ve supplied both a hexadecimal and an octal number. Using them in an expression results in their decimal equivalents. The example has the following output:
0x14 = 20
O101 = 65
Unfortunately, VBScript doesn’t provide a nice way of handling binary data. It’s best to create a function that can do that for you whenever the need arises. Remember how easy we found it was to convert binary to hexadecimal earlier? You should be able to build a converter function with that knowledge.
Hint: Treat your numbers as strings using the functions you’ll find later in this article!
Now that you have a better understanding of how number systems work—and how they are treated by VBScript—we can begin to discuss how to convert between different data types as well as how they are handled and evaluated in expressions.
Converting between data types is known as casting. VBScript will do this automatically in most cases; however, it can lead to some unexpected results. It is a much better practice to make explicit casts using the conversion functions provided by VBScript.
Asc(string) 'Returns the ANSI character code corresponding to
the first letter in a string
CBool(expression) 'Returns an expression converted to type Boolean
CByte(expression) 'Returns an expression converted to type Byte
CCur(expression) 'Returns an expression converted to type Currency
CDate(date) 'Returns an expression converted to type Date
CDbl(expression) 'Returns an expression converted to type Double
Chr(charcode) 'Returns the character associated with a specified
ANSI character code
CInt(expression) 'Returns an expression converted to type Integer
CLng(expression) 'Returns an expression converted to type Long
CSng(expression) 'Returns an expression converted to type Single
CStr(expression) 'Returns an expression as a string
Each of the “C” functions, with exception of Chr() and CStr(), is used for casting. Note that if you cast to a narrowing type, some loss of precision will occur. For example, if you cast a double such as 32,450.32 to an Integer, your result will be 32,450. Precision will be preserved, however, when casting to a wider subtype.
The Asc and Chr functions are used to handle ANSI characters. The Chr function returns a character represented by a given ANSI character code while Asc returns the character code for a given character.
MyChar = "F"
MyCharCode = "35"
Asc(MyChar) 'Returns 70
Chr(MyCharCode) ‘Returns "#"
Use caution when building expression that are designed to be evaluated mathematically. If you mix data types in a mathematical expression, VBScript will convert all values to the widest type before evaluating the expression. The expression will return the widest type.
This example demonstrates a calculation using mixed data subtypes. The narrower Integer is first converted to the wider Double type before VBScript makes the calculation. The result is the wider type—Double.
Let’s take a few moments to discuss the String subtype. Strings are a string of ANSI characters. (Or Unicode, if that is the system default.) These are human readable bit patterns consisting of 2-bit character codes for each character in the string. That being said, the CStr function returns some unusual values in some cases.
If expression is
CStr returns
Boolean
A String containing True or False.
Date
A String containing a date in the short-date format of your system.
Null
A run-time error.
Empty
A zero-length String ("").
Error
A String containing the word Error followed by the error number.
Other numeric
A String containing the number.
The final data types to consider are the special Currency and Date subtypes. These are used for performing calculations with values of the given types.
MyDate1 = #12 / 25 / 00#
MyDate2 = #12 / 1 / 00#
MyResult = MyDate1 - MyDate2 'Returns 24
The expression above returns the number of days between the given dates. In this case, that number is 24. Notice how I’ve used the # notation to indicate that my values are dates. Since this returns a Date object, I could also use any of the available date functions on my returned value.
CCur(1.25 + 1.9545678) 'Returns 3.2046
This example demonstrates a currency calculation. Notice how the result is rounded up to represent thousandths of a whole dollar.
Finally, I’d like to take a minute to revisit the floating point data types that I showed you previously. VBScript provides two functions that allow you to convert (or round) them into integer types.
Int(number)
Fix(number)
Both the Int and Fix functions allow you to remove the decimal portion of a floating point number (by rounding down to the nearest integer). They differ is how they do this with negative numbers.
MyNumber = Int(99.8) ' Returns 99.
MyNumber = Fix(99.2) ' Returns 99.
MyNumber = Int(-99.8) ' Returns -100.
MyNumber = Fix(-99.8) ' Returns -99.
MyNumber = Int(-99.2) ' Returns -100.
MyNumber = Fix(-99.2) ' Returns -99.
The Int function returns the nearest integer less than the given number while the Fix function returns the nearest integer greater than the given number. Another way of looking at this is that Int will always round down to the nearest integer while Fix simply removes the decimal portion leaving the integer portion unchanged.
Now you’ve learned about the different number systems available in VBScript and how they affect the different data subtypes. This understanding should enable you to make more accurate calculations while allowing you to handle all different types of data in your script.
If this seems like a lot to take in, that’s because it is. Take the time to read through this article again and you’ll be more apt to understand the concepts I’ve presented. Take your time, experiment with the different conversion functions to see what they return, and remember to have fun.