How do I limit BitConverter.GetBytes() to return only a certain amount of bytes using VB.NET? - vb.net

I do:
Dim BytArr() as Byte = BitConverter.GetBytes(1234)
Since, by default, they are 32 bits, it returns 4 byte elements.
I want to be able to control it to return only like two bytes. Maybe only three bytes. Are there any built-in functions to control it?
I don't want to rely on using shifting >> 8 >> 16 >> 24 >> 32, etc..
I also don't want to rely on type casting the data in GetBytes() to a specific datatype.

It is not that GetBytes defaults to 32 bits, it is that GetBytes returns an array of the size required to hold the data type. If you pass a Long then you will get a 8 elements in your array.
The best way to control this is indeed casting the data you pass in. Otherwise you could truncate some of the number.
That being said, you could do something like this:
Dim BytArr() as Byte = Array.Resize(BitConverter.GetBytes(1234), 2)
But if the value you passed in exceeded what could be stored in 2 bytes (in this case) then you will have some very broken code.

Related

How to manipulate bits in Smalltalk?

I am currently working on a file compressor based on Huffman decoding. So I have a decoding tree like so:
and I have to encode this tree on an output file by following a certain criteria:
"for each leaf, write out a 0 bit, followed by the 8 bits of
the corresponding character. Write out the bits in the order bit 7, bit 6, . . ., bit 0, that is high bit first. As a special case, if the byte is 0, write out bit 8, which will be a 0 for a byte value of 0, and 1 for a byte value of 256 (the EOF marker)." For an internal node, just write a bit 1.
So what I plan to do is to create a bit array and add to it the corresponding bits in the specified format. The problem is that I don't know how to convert a number to binary in smalltalk.
For example, if I want to encode the first leaf, I would want to do something like 01101011 i.e 0 followed by the bit representation of k and then add every bit one by one into the array.
I don't know which dialect you are using exactly, but generally, you can access the bits of Integer. They are modelled as if the representation was in two-complement, with an infinite sequence of bits.
2 is ....0000000000010
1 is ....0000000000001
0 is ....0000000000000 with infinitely many 0 on the left
-1 is ....1111111111111 with infinitely many 1 on the left
-2 is ....1111111111110
This is also true for LargeIntegers, even though they are generally implemented as sign magnitude (the class encodes the sign), two-complement will be emulated.
Then you can operate with bitAnd: bitOr: bitXor: bitInvert bitShift:, and in some flavours bitAt:put:
You can access the bits with (2 bitAt: index) where the index starts at 1 for least significant bit, or grows higher. If it's missing, implement it with bitAnd: and bitShift:...
For positive, you can ask for the rank of high bit (2 highBit).
All these operations should create a new integer (there's no in place modification possible).
Conceptually, a ByteArray is a collection of unsigned integers on 8 bits (between 0 and 255), so you can implement a bit Array with them (if it does not already exist in the dialect). Or you can use an Integer (but won't be able to control size which will be infinite, nor in place mofifications, operations will cost a copy).

Fail at sending byte array through serial port excel-vba

I am trying to get information from an Excel worksheet and send it through a serial port as a byte array, using Windows API. This is just a small part of it:
lngSize = UBound(byteData) - LBound(byteData)
WriteFile(udtPorts(intPortID).lngHandle, byteData, lngSize, _lngWrSize, udtCommOverlap)
My current problem: when I am sending a byte array of length 1 (just one byte), I receive it correctly (I am using a hyperterminal to check what I'm sending), but when I send an array of length > 1, here comes the problem; instead of receiving it like this:
letter = 65
For i = 0 To 5
dataToSend(i) = letter
letter = letter + 1
Next
what I should receive
what I get is this:
what I receive
I really cannot figure out what could be the problem and I would be grateful if someone had a clue. Thank you!
First, the correct number of elements in an array is:
lngSize = UBound(byteData) - LBound(byteData) + 1 ' <-- add 1
More importantly, your code is not applying the call convention for the WriteFile API. Namely, the second parameter should be a LPCVOID pointer to the first Byte to transfer. Passing the array's name byteData to the function wont achieve that, because the array is a complex COM data structure, not like a C array. What you should do is:
First get the address of the array's data structure, using VarPtrArray:
Then add 12 to it to get the address of the first byte.
.
Private Declare Function VarPtrArray Lib "VBE7" Alias "VarPtr" (var () As Any) As Long
...
WriteFile(udtPorts(intPortID).lngHandle, VarPtrArray(byteData()) + 12, lngSize, _lngWrSize, udtCommOverlap)
' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
For information about handling arrays' data and their pointers, excellent examples can be found [on this page].(https://www.codeproject.com/Articles/729235/VB-and-VBA-Array-Buffering)
Also make sure that you declared you array as a Byte array, like
Redim byteData(someSize) As Byte
' ^^^^^^^
There might be other errors in the parts of code you didn't show (possibly the settings of udtCommOverlap), but hopefully these corrections will put you on the right track.

Convert audio doubles to bytes

I am dealing with raw PCM audio data (the audio data of a PCM file without the header).
This data is provided to me in the form of a vector of double.
I would like to pass this data to another function, and this function expects the audio data in the form of a byte vector.
I tried
Dim nBytes() As Byte = nDoubles.SelectMany(Function(d) BitConverter.GetBytes(d)).ToArray()
but that wouldn't give the expected results.
I guess I have to deal with the conversion manually, but I am unsure how this should be done.
Can anybody help?
Thank you.
Since the required format for the other function is 16-bit, 48 kHz, which is the same as your source data, it's a simple case of converting the source to an array of Short, then serializing this as a Byte array.
The problem with the code you suggest for this is that the first step is missed, so it basically serializes the Double array. However, you can re-use this for the second step. So, you can do something like:
Dim nShorts() As Short = New Short(nDoubles.Length - 1) {}
For i = 0 To nDoubles.Length - 1
nShorts(i) = Convert.ToInt16(nDoubles(i))
Next
Dim nBytes() As Byte = nShorts.SelectMany(Function(s) BitConverter.GetBytes(s)).ToArray()

Storing integers in a redis ordered set?

I have a system which deals with keys that have been turned into unsigned long integers (by packing short sequences into byte strings). I want to try storing these in Redis, and I want to do it in the best way possible. My concern is mainly memory efficiency.
From playing with the online REPL I notice that the two following are identical
zadd myset 1.0 "123"
zadd myset 1.0 123
This means that even if I know I want to store an integer, it has to be set as a string. I notice from the documentation that keys are just stored as char*s and that commands like SETBIT indicate that Redis is not averse to treating strings as bytestrings in the client. This hints at a slightly more efficient way of storing unsigned longs than as their string representation.
What is the best way to store unsigned longs in sorted sets?
Thanks to Andre for his answer. Here are my findings.
Storing ints directly
Redis keys must be strings. If you want to pass an integer, it has to be some kind of string. For small, well-defined sets of values, Redis will parse the string into an integer, if it is one. My guess is that it will use this int to tailor its hash function (or even statically dimension a hash table based on the value). This works for small values (examples being the default values of 64 entries of a value of up to 512). I will test for larger values during my investigation.
http://redis.io/topics/memory-optimization
Storing as strings
The alternative is squashing the integer so it looks like a string.
It looks like it is possible to use any byte string as a key.
For my application's case it actually didn't make that much difference storing the strings or the integers. I imagine that the structure in Redis undergoes some kind of alignment anyway, so there may be some pre-wasted bytes anyway. The value is hashed in any case.
Using Python for my testing, so I was able to create the values using the struct.pack. long longs weigh in at 8 bytes, which is quite large. Given the distribution of integer values, I discovered that it could actually be advantageous to store the strings, especially when coded in hex.
As redis strings are "Pascal-style":
struct sdshdr {
long len;
long free;
char buf[];
};
and given that we can store anything in there, I did a bit of extra Python to code the type into the shortest possible type:
def do_pack(prefix, number):
"""
Pack the number into the best possible string. With a prefix char.
"""
# char
if number < (1 << 8*1):
return pack("!cB", prefix, number)
# ushort
elif number < (1 << 8*2):
return pack("!cH", prefix, number)
# uint
elif number < (1 << 8*4):
return pack("!cI", prefix, number)
# ulonglong
elif number < (1 << 8*8):
return pack("!cQ", prefix, number)
This appears to make an insignificant saving (or none at all). Probably due to struct padding in Redis. This also drives Python CPU through the roof, making it somewhat unattractive.
The data I was working with was 200000 zsets of consecutive integer => (weight, random integer) × 100, plus some inverted index (based on random data). dbsize yields 1,200,001 keys.
Final memory use of server: 1.28 GB RAM, 1.32 Virtual. Various tweaks made a difference of no more than 10 megabytes either way.
So my conclusion:
Don't bother encoding into fixed-size data types. Just store the integer as a string, in hex if you want. It won't make all that much difference.
References:
http://docs.python.org/library/struct.html
http://redis.io/topics/internals-sds
I'm not sure of this answer, it's more of a suggestion than anything else. I'd have to give it a try and see if it works.
As far as I can tell, Redis only supports UTF-8 strings.
I would suggest grabbing a bit representation of your long integer and pad it accordingly to fill up the nearest byte. Encode each set of 8 bytes to a UTF-8 string (ending up with 8x*utf8_char* string) and store that in Redis. The fact that they're unsigned means that you don't care about that first bit but if you did, you could add a flag to the string.
Upon retrieving the data, you have to remember to pad each character to 8 bytes again as UTF-8 will use less bytes for the representation if the character can be stored with less bytes.
End result is that you store a maximum of 8 x 8 byte characters instead of (possibly) a maximum of 64 x 8 byte characters.

How can I do a bitwise-AND operation in VB.NET?

I want to perform a bitwise-AND operation in VB.NET, taking a Short (16-bit) variable and ANDing it with '0000000011111111' (thereby retaining only the least-significant byte / 8 least-significant bits).
How can I do it?
0000000011111111 represented as a VB hex literal is &HFF (or &H00FF if you want to be explicit), and the ordinary AND operator is actually a bitwise operator. So to mask off the top byte of a Short you'd write:
shortVal = shortVal AND &HFF
For more creative ways of getting a binary constant into VB, see: VB.NET Assigning a binary constant
Use the And operator, and write the literal in hexadecimal (easy conversion from binary):
theShort = theShort And &h00ff
If what you are actually trying to do is to divide the short into bytes, there is a built in method for that:
Dim bytes As Byte() = BitConverter.GetBytes(theShort)
Now you have an array with two bytes.
result = YourVar AND cshort('0000000011111111')