This package contains a large set of library routines I have built over the years to do many things related to numbers. These routines run in VB6 as well as 32 or 64-bit VBA. As you know, there are often multiple ways of solving a problem. I have been building these utilities for 20+ years and I often work on speed, accuracy and functionality for all of them. If you have any procedures that you think are better than those I have in this package please let me know so I can upgrade the library.
A lot of the routines use normal VB code. For some I have used RtlMoveMemory (many of you use an alias of CopyMemory for this Windows API function) to facilitate things like shifting bits, copying to other data types (e.g., getting the top byte of a Long variable into a Byte) etc.
In general I have found that I do not include an entire module but rather use specific ones you need in my code.
The package consists of 9 modules and is there are no dependencies. Most of the subs and functions are self-explanatory but each is briefly discussed below. BTW, if you use any of this in Excel as User Defined Functions, you can greatly improve the time lag in the workbook by putting the Application.Volatile False at the top of whatever function(s) are using in the spreadsheet.
At the end of this document are instructions for running the sample code.
mBaseConversions
This module allows for conversion between regular numbers, hexadecimal and binary.
This module makes use of a variable I call UVar which represents an unsigned Currency which allows us to use all 64 bits of the number. If you are using 64-bit VBA then you can also think of UVar as an unsigned LongLong (also 64 bits). A UVar can be a Byte, Integer, Long, Currency, Single, Double, Decimal (part of a Variant) and a LongLong (64-bit only).
What you submit to this function (and the others in this module) are treated as unsigned values. As you know, VB uses the top bit of scalar variables to designate the sign. We ignore that and treat the topmost bit as just another bit. For example, the hex value of -1 as a Long is &HFFFF (i.e., all bits are set). BTW, you cant avoid the top bit being used for the sign. It would be tempting to think you can take and integer value of -1 and use the function to convert it to a Long that the full 16 bits would go to the Long. Unfortunately, VB doesnt do that. Instead, VB converts the Integer -1 to a Long -1 (all 32 bits in the Long are set whereas only 16 bits were set in the Integer. For normal use this is okay but when we want to use all of the bits in hex or binary, this is a problem. Other than a Byte, VB doesnt have any unsigned variables so thats what we deal with here.
One interesting thing occurs with the Currency variable. Even though it is an integer type variable, it has a decimal component. VB does this by taking the value given it an multiplying by 10,000 and then it uses the lower bits to do the fractional part. Internally it is just a 64-bit value and the multiplying and dividing by 10,000 is done when a value is assigned or the conversion function CCur is used. We treat a Currency value as an unsigned 64-bit value. If you have a regular Currency variable and you want to feed it to UVar2Hex or UVar2Bin then you should first divide it by 10,000. Likewise, if you use Hex2UVar or Bin2UVar and you want to use the return Currency value for other calculations you should multiply it by 10,000.
If you use this in 64-bit Office you have access to a signed 64-bit variable called a LongLong that does not have the 10,000 factor that the Currency data type has. The only thing to watch out for is that it is a signed variable (i.e., the topmost of the 64 bits is the sign bit).
UVar can also be a Single, Double or a Decimal value but note that when you use UVar2Hex or UVar2Bin with a negative number it gets converted to a signed value. For example, if you have a Double variable with a value of -1, when it gets converted it will become an integer (Currency or LongLong) with a value of -1. If thats what you wanted thats fine but just know that with anything other than a Byte data type, you have to be aware that VB messes around with the topmost bit. It would be nice if VB had unsigned variables but it doesnt so this is why I created this set or procedures.
Function UVar2Hex Return a hex string from the UVar. The return will have no leading zeroes (e.g., Feeding it a Long value of 10000000& returns 98 9680 and not 0098 9680). You can determine whether to group the return characters, and if so, how much (the example in the previous was based on the default grouping of 4 characters).
The function specifies the input variable is a Variant but you can use whatever data type you want without first converting it to a variant (I believe VB does that internally).
Function Hex2UVar Convert a hex string (up to 16 characters (64-bit)) into an unsigned value. You can specify a data type or take the default which is to determine the data type from the size of the value. For example, if you pass F as the hex string, you could specify for it to be returned as a byte, integer, long, etc. but if you go with the default it will be returned as a byte inside the variant.
Function UVar2Bin Converts an unsigned variable into its binary equivalent (as a string). For a Byte, Integer, Long, Currency, LongLong, Single, Double or Decimal returns the string representation of the binary number (base 2). Since the routine uses an unsigned value, if you use a Currency then it should first be divided by 10,000 (or as part of the call) to use all of the bits.
There is an optional parameter named RndType (optional) determines the size of the return number (higher bits are discarded from return). For example, if you pass an integer with a value of 111, this function will return 00000000 01101111 but if you set RndType to 1 to indicate a Byte, the function will return 01101111. You can specify what character (or none at all) to sue as the leading character. For example, if you specify no leading character, the return from the previous example will be 1101111. Finally, you can set the grouping. The previous examples use a grouping of 8 characters. If you specify 0 there is no grouping and the string is returned without any spacing characters.
Function Bin2UVar - Returns the variable related to the binary string of up to 64 characters (1s and 0s). Must specify the variant variable type in "VarType" (vbByte, vbInteger, vbLong, vbCurrency or vbLongLong) and the return is adjusted for the type of variable. If you do not specify this value then the function determines it from the length of the input binary string (1-8 byte, 9-16 integer, 17-32 long, 33-64 currency or longlong).
Function Hex2Bin - Converts a hex string into its binary counterpart. As discussed above, you can also specify the leading character (defaults to 0) or you can not have leading zeroes by specifying . You can also set the grouping of binary characters in the return (default 8 characters which is 1 byte).
Function Bin2Hex - Converts a binary string of up to 64 characters (all 0's and 1's) into a hex string.
Module mBaseConversions1
The previous module has very flexible routines for converting between base 10, hexadecimal and binary numbers. If you want type-specific solutions that have fewer frills, the following conversions could be used.
Byte2Hex Returns the hexadecimal representation of a Byte with optional leading 0s.
Int2Hex Converts an Integer into a Hex.
Long2Curr Converts an unsigned Long to a Currency.
Long2UCurr Returns an unsigned Currency with the Long in the low order bytes.
Long2Bin1 Converts a Long into a binary string. Same functionality as Bin2Hex in module mBaseConversions but uses different logic & has a different name to avoid duplicate names in the same project.
Long2Hex Converts a Long variable into a Hex string.
Curr2Hex Converts a Currency into a hex string.
Curr2Bin Converts a Currency into a binary string.
UCurr2Hex - An unsigned Currency (if it is a normal Currency, it should be divided by 10,000). This function converts this unsigned Currency into a Hex string.
Bin2Byte Converts a binary string into a Byte.
Bin2Int Converts a binary string into an unsigned integer (uses last 16 bits).
Bin2Long Converts a binary string into a Long.
Bin2Curr Converts a binary string into a Currency. Unlike Bin2UVar, this one returns the Currency without using the last 4 bits (i.e. not divided by 10,000).
Bin2UCurr Converts a binary string into the unsigned Currency.
Bin2Hex1 Converts a binary string into its hex equivalent. Same functionality as Bin2Hex in module mBaseConversions but uses different logic & has a different name to avoid duplicate names in the same project.
Hex2Curr Converts a hex string into a Currency.
Double2Hex Converts a Double into its hex equivalent.
If you are using 64-bit VBA you also have the following procedures:
Long2LL Converts an unsigned Long into an unsigned LongLong.
LLToHex Converts an unsigned LongLong into its Hex equivalent.
Bin2LL Converts a binary string into an unsigned LongLong (string, max 62 chars)
Hex2LL Converts a hex String (up to 15 characters) into an unsigned LongLong.
LL2Hex Converts an unsigned LongLong into hex.
LL2Bin Converts an unsigned LongLong into a binary string.
Module mDataTypeConversions
This module works with sub-parts of variables. For example, one function takes all 4 bytes of a Long and puts them into 4 Byte variables.
Bytes2Int Puts 2 Bytes into the 2 bytes of an Integer.
Bytes2Long Puts 4 Bytes into one Long.
Bytes2UCurr Combines 8 Bytes into a Currency (not multiplied by 10,000).
Int2Bytes Puts the 2 bytes of an Integer into 2 Bytes.
Ints2Long Puts 2 Integers into a Long.
Ints2UCurr Combines 4 Integers into a Currency (not multiplied by 10,000).
Int2LoByte - Returns the low byte (least significant byte) of "Integer1"
Int2HiByte - Returns the high byte (most significant byte) of "Integer1"
Long2Byte - Puts the specified byte (1=least significant byte, 4=most significant byte from a Long into a Byte.
Long2Bytes Puts the 4 bytes of a Long into 4 Bytes.
Long2Ints Puts the two integers making up the most and least significant words of a Long into 2 Integers.
LongToUCurr - Takes a long (unsigned but contained in a signed long) like from an API call & returns it in a U64 (NOT multiplied by 10,000). Note the top 4 bytes of the U64 value will always be 0 by definition.
Longs2UCurr Combines 2 Words into a Currency (not multiplied by 10,000).
Long2LoWord - Returns the low integer (least significant word) of a Long into an Integer.
Long2HiWord - Returns the high integer (most significant word) of a Long into an Integer.
Long2CurrLo Puts a Long into the low 4 bytes of a Currency (hi bits are 0).
Curr2UCurr - Takes a Currency that VB has already multiplied by 10000. Existing fractional part is discarded.
UCurr2Bytes Puts the 8 bytes of a Currency (not divided by 10,000) into 8 Bytes.
UCurr2Ints Puts the 8 bytes of a Currency (not divided by 10,000) into 4 Integers.
UCurr2Longs Puts the 8 bytes of a Currency (not divided by 10,000) into 2 Longs.
UCurr2Byte Puts the selected byte of a Currency into a Byte.
UCurr2Int Puts the selected word of a Currency into an Integer.
UCurr2LoLong - Returns the low long (least significant long) of a Currency.
UCurr2HiLong - Returns the high long (most significant long) of a Currency.
UCurrToCurr - Takes a 64-bit value that VB has NOT multiplied by 10,000 and does that to the number (for display & non-bit calculations).
If you are using 64-bit VBA you also have the following procedures:
LL2Bytes Puts the 8 bytes of a LongLong into 8 Bytes.
LL2Ints Puts the 8 bytes of a LongLong into 4 Integers.
LL2Longs Puts the 8 bytes of a LongLong into 2 Longs.
Bytes2LL Puts 8 Bytes into a LongLong.
Ints2LL Combines 4 Integers into a LongLong.
Longs2LL Combines 2 Longs into a LongLong.
Long2LLLo Puts the 4 bytes of a Long into the low 4 bits of a LongLong (hi 4 bytes are 0d).
LL2Byte - Puts the specified byte (1=least significant byte, 8=most significant byte out of a LongLong into a Byte.
LL2Int - Puts the specified integer (1=least significant integer, 4=most significant integer out of a LongLong into an Integer.
LL2LoLong - Puts the low long (least significant long) of a LongLong into a Long.
LL2HiLong Puts the most significant 4 bytes of a LongLong into a Long.
Numbers.zip
{Continued in next post}
A lot of the routines use normal VB code. For some I have used RtlMoveMemory (many of you use an alias of CopyMemory for this Windows API function) to facilitate things like shifting bits, copying to other data types (e.g., getting the top byte of a Long variable into a Byte) etc.
In general I have found that I do not include an entire module but rather use specific ones you need in my code.
The package consists of 9 modules and is there are no dependencies. Most of the subs and functions are self-explanatory but each is briefly discussed below. BTW, if you use any of this in Excel as User Defined Functions, you can greatly improve the time lag in the workbook by putting the Application.Volatile False at the top of whatever function(s) are using in the spreadsheet.
At the end of this document are instructions for running the sample code.
mBaseConversions
This module allows for conversion between regular numbers, hexadecimal and binary.
This module makes use of a variable I call UVar which represents an unsigned Currency which allows us to use all 64 bits of the number. If you are using 64-bit VBA then you can also think of UVar as an unsigned LongLong (also 64 bits). A UVar can be a Byte, Integer, Long, Currency, Single, Double, Decimal (part of a Variant) and a LongLong (64-bit only).
What you submit to this function (and the others in this module) are treated as unsigned values. As you know, VB uses the top bit of scalar variables to designate the sign. We ignore that and treat the topmost bit as just another bit. For example, the hex value of -1 as a Long is &HFFFF (i.e., all bits are set). BTW, you cant avoid the top bit being used for the sign. It would be tempting to think you can take and integer value of -1 and use the function to convert it to a Long that the full 16 bits would go to the Long. Unfortunately, VB doesnt do that. Instead, VB converts the Integer -1 to a Long -1 (all 32 bits in the Long are set whereas only 16 bits were set in the Integer. For normal use this is okay but when we want to use all of the bits in hex or binary, this is a problem. Other than a Byte, VB doesnt have any unsigned variables so thats what we deal with here.
One interesting thing occurs with the Currency variable. Even though it is an integer type variable, it has a decimal component. VB does this by taking the value given it an multiplying by 10,000 and then it uses the lower bits to do the fractional part. Internally it is just a 64-bit value and the multiplying and dividing by 10,000 is done when a value is assigned or the conversion function CCur is used. We treat a Currency value as an unsigned 64-bit value. If you have a regular Currency variable and you want to feed it to UVar2Hex or UVar2Bin then you should first divide it by 10,000. Likewise, if you use Hex2UVar or Bin2UVar and you want to use the return Currency value for other calculations you should multiply it by 10,000.
If you use this in 64-bit Office you have access to a signed 64-bit variable called a LongLong that does not have the 10,000 factor that the Currency data type has. The only thing to watch out for is that it is a signed variable (i.e., the topmost of the 64 bits is the sign bit).
UVar can also be a Single, Double or a Decimal value but note that when you use UVar2Hex or UVar2Bin with a negative number it gets converted to a signed value. For example, if you have a Double variable with a value of -1, when it gets converted it will become an integer (Currency or LongLong) with a value of -1. If thats what you wanted thats fine but just know that with anything other than a Byte data type, you have to be aware that VB messes around with the topmost bit. It would be nice if VB had unsigned variables but it doesnt so this is why I created this set or procedures.
Function UVar2Hex Return a hex string from the UVar. The return will have no leading zeroes (e.g., Feeding it a Long value of 10000000& returns 98 9680 and not 0098 9680). You can determine whether to group the return characters, and if so, how much (the example in the previous was based on the default grouping of 4 characters).
The function specifies the input variable is a Variant but you can use whatever data type you want without first converting it to a variant (I believe VB does that internally).
Function Hex2UVar Convert a hex string (up to 16 characters (64-bit)) into an unsigned value. You can specify a data type or take the default which is to determine the data type from the size of the value. For example, if you pass F as the hex string, you could specify for it to be returned as a byte, integer, long, etc. but if you go with the default it will be returned as a byte inside the variant.
Function UVar2Bin Converts an unsigned variable into its binary equivalent (as a string). For a Byte, Integer, Long, Currency, LongLong, Single, Double or Decimal returns the string representation of the binary number (base 2). Since the routine uses an unsigned value, if you use a Currency then it should first be divided by 10,000 (or as part of the call) to use all of the bits.
There is an optional parameter named RndType (optional) determines the size of the return number (higher bits are discarded from return). For example, if you pass an integer with a value of 111, this function will return 00000000 01101111 but if you set RndType to 1 to indicate a Byte, the function will return 01101111. You can specify what character (or none at all) to sue as the leading character. For example, if you specify no leading character, the return from the previous example will be 1101111. Finally, you can set the grouping. The previous examples use a grouping of 8 characters. If you specify 0 there is no grouping and the string is returned without any spacing characters.
Function Bin2UVar - Returns the variable related to the binary string of up to 64 characters (1s and 0s). Must specify the variant variable type in "VarType" (vbByte, vbInteger, vbLong, vbCurrency or vbLongLong) and the return is adjusted for the type of variable. If you do not specify this value then the function determines it from the length of the input binary string (1-8 byte, 9-16 integer, 17-32 long, 33-64 currency or longlong).
Function Hex2Bin - Converts a hex string into its binary counterpart. As discussed above, you can also specify the leading character (defaults to 0) or you can not have leading zeroes by specifying . You can also set the grouping of binary characters in the return (default 8 characters which is 1 byte).
Function Bin2Hex - Converts a binary string of up to 64 characters (all 0's and 1's) into a hex string.
Module mBaseConversions1
The previous module has very flexible routines for converting between base 10, hexadecimal and binary numbers. If you want type-specific solutions that have fewer frills, the following conversions could be used.
Byte2Hex Returns the hexadecimal representation of a Byte with optional leading 0s.
Int2Hex Converts an Integer into a Hex.
Long2Curr Converts an unsigned Long to a Currency.
Long2UCurr Returns an unsigned Currency with the Long in the low order bytes.
Long2Bin1 Converts a Long into a binary string. Same functionality as Bin2Hex in module mBaseConversions but uses different logic & has a different name to avoid duplicate names in the same project.
Long2Hex Converts a Long variable into a Hex string.
Curr2Hex Converts a Currency into a hex string.
Curr2Bin Converts a Currency into a binary string.
UCurr2Hex - An unsigned Currency (if it is a normal Currency, it should be divided by 10,000). This function converts this unsigned Currency into a Hex string.
Bin2Byte Converts a binary string into a Byte.
Bin2Int Converts a binary string into an unsigned integer (uses last 16 bits).
Bin2Long Converts a binary string into a Long.
Bin2Curr Converts a binary string into a Currency. Unlike Bin2UVar, this one returns the Currency without using the last 4 bits (i.e. not divided by 10,000).
Bin2UCurr Converts a binary string into the unsigned Currency.
Bin2Hex1 Converts a binary string into its hex equivalent. Same functionality as Bin2Hex in module mBaseConversions but uses different logic & has a different name to avoid duplicate names in the same project.
Hex2Curr Converts a hex string into a Currency.
Double2Hex Converts a Double into its hex equivalent.
If you are using 64-bit VBA you also have the following procedures:
Long2LL Converts an unsigned Long into an unsigned LongLong.
LLToHex Converts an unsigned LongLong into its Hex equivalent.
Bin2LL Converts a binary string into an unsigned LongLong (string, max 62 chars)
Hex2LL Converts a hex String (up to 15 characters) into an unsigned LongLong.
LL2Hex Converts an unsigned LongLong into hex.
LL2Bin Converts an unsigned LongLong into a binary string.
Module mDataTypeConversions
This module works with sub-parts of variables. For example, one function takes all 4 bytes of a Long and puts them into 4 Byte variables.
Bytes2Int Puts 2 Bytes into the 2 bytes of an Integer.
Bytes2Long Puts 4 Bytes into one Long.
Bytes2UCurr Combines 8 Bytes into a Currency (not multiplied by 10,000).
Int2Bytes Puts the 2 bytes of an Integer into 2 Bytes.
Ints2Long Puts 2 Integers into a Long.
Ints2UCurr Combines 4 Integers into a Currency (not multiplied by 10,000).
Int2LoByte - Returns the low byte (least significant byte) of "Integer1"
Int2HiByte - Returns the high byte (most significant byte) of "Integer1"
Long2Byte - Puts the specified byte (1=least significant byte, 4=most significant byte from a Long into a Byte.
Long2Bytes Puts the 4 bytes of a Long into 4 Bytes.
Long2Ints Puts the two integers making up the most and least significant words of a Long into 2 Integers.
LongToUCurr - Takes a long (unsigned but contained in a signed long) like from an API call & returns it in a U64 (NOT multiplied by 10,000). Note the top 4 bytes of the U64 value will always be 0 by definition.
Longs2UCurr Combines 2 Words into a Currency (not multiplied by 10,000).
Long2LoWord - Returns the low integer (least significant word) of a Long into an Integer.
Long2HiWord - Returns the high integer (most significant word) of a Long into an Integer.
Long2CurrLo Puts a Long into the low 4 bytes of a Currency (hi bits are 0).
Curr2UCurr - Takes a Currency that VB has already multiplied by 10000. Existing fractional part is discarded.
UCurr2Bytes Puts the 8 bytes of a Currency (not divided by 10,000) into 8 Bytes.
UCurr2Ints Puts the 8 bytes of a Currency (not divided by 10,000) into 4 Integers.
UCurr2Longs Puts the 8 bytes of a Currency (not divided by 10,000) into 2 Longs.
UCurr2Byte Puts the selected byte of a Currency into a Byte.
UCurr2Int Puts the selected word of a Currency into an Integer.
UCurr2LoLong - Returns the low long (least significant long) of a Currency.
UCurr2HiLong - Returns the high long (most significant long) of a Currency.
UCurrToCurr - Takes a 64-bit value that VB has NOT multiplied by 10,000 and does that to the number (for display & non-bit calculations).
If you are using 64-bit VBA you also have the following procedures:
LL2Bytes Puts the 8 bytes of a LongLong into 8 Bytes.
LL2Ints Puts the 8 bytes of a LongLong into 4 Integers.
LL2Longs Puts the 8 bytes of a LongLong into 2 Longs.
Bytes2LL Puts 8 Bytes into a LongLong.
Ints2LL Combines 4 Integers into a LongLong.
Longs2LL Combines 2 Longs into a LongLong.
Long2LLLo Puts the 4 bytes of a Long into the low 4 bits of a LongLong (hi 4 bytes are 0d).
LL2Byte - Puts the specified byte (1=least significant byte, 8=most significant byte out of a LongLong into a Byte.
LL2Int - Puts the specified integer (1=least significant integer, 4=most significant integer out of a LongLong into an Integer.
LL2LoLong - Puts the low long (least significant long) of a LongLong into a Long.
LL2HiLong Puts the most significant 4 bytes of a LongLong into a Long.
Numbers.zip
{Continued in next post}