VB.NET - How to calculate the parity bit of a byte array - vb.net

What is the most efficient way calculate the parity bit (if the number of active bits are odd or even) in a byte array? I have though about iterating through all the bits and summing up the active bits, but that would be very impractical purely based on the number of iterations required on larger byte arrays/files.

For your convenience (and my curiosity), I have done some timing tests with a parity lookup table compared to the other two methods suggested so far:
Module Module1
Dim rand As New Random
Dim parityLookup(255) As Integer
Sub SetUpParityLookup()
' setBitsCount data from http://stackoverflow.com/questions/109023/how-to-count-the-number-of-set-bits-in-a-32-bit-integer
Dim setBitsCount = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
}
For i = 0 To 255
parityLookup(i) = setBitsCount(i) And 1
Next
End Sub
' Method using lookup table
Function ParityOfArray(a() As Byte) As Integer
Dim parity As Integer = 0 ' use an Integer because they are faster
For i = 0 To a.Length - 1
parity = parity Xor parityLookup(a(i))
Next
Return parity
End Function
' Method by Alireza
Function ComputeParity(bytes() As Byte) As Byte
Dim parity As Boolean = False
For i As Integer = 0 To bytes.Length - 1
Dim b As Byte = bytes(i)
While b <> 0
parity = Not parity
b = CByte(b And (b - 1))
End While
Next
Return Convert.ToByte(parity)
End Function
' Method by dbasnett
Function CountBits(byteArray As Byte()) As Integer
Dim rv As Integer = 0
For Each b As Byte In byteArray
Dim count As Integer = b
count = ((count >> 1) And &H55) + (count And &H55)
count = ((count >> 2) And &H33) + (count And &H33)
count = ((count >> 4) And &HF) + (count And &HF)
rv += count
Next
Return rv
End Function
Sub FillWithRandomBytes(ByRef a() As Byte)
rand.NextBytes(a)
End Sub
Sub Main()
SetUpParityLookup()
Dim nBytes = 10000
Dim a(nBytes - 1) As Byte
FillWithRandomBytes(a)
Dim p As Integer
Dim sw As New Stopwatch
sw.Start()
p = ParityOfArray(a)
sw.Stop()
Console.WriteLine("ParityOfArray - Parity: {0} Time: {1}", p, sw.ElapsedTicks)
sw.Restart()
p = ComputeParity(a)
sw.Stop()
Console.WriteLine("ComputeParity - Parity: {0} Time: {1}", p, sw.ElapsedTicks)
sw.Restart()
p = CountBits(a)
sw.Stop()
' Note that the value returned from CountBits should be And-ed with 1.
Console.WriteLine("CountBits - Parity: {0} Time: {1}", p And 1, sw.ElapsedTicks)
Console.ReadLine()
End Sub
End Module
Typical ouput:
ParityOfArray - Parity: 0 Time: 386
ComputeParity - Parity: 0 Time: 1014
CountBits - Parity: 0 Time: 695

An efficient way to do this is to use the x & (x - 1) operation in a loop, until x becomes zero. This way you will loop only by the number of bits set to 1.
In VB.NET for a byte array:
Function ComputeParity(bytes() As Byte) As Byte
Dim parity As Boolean = False
For i As Integer = 0 To bytes.Length - 1
Dim b As Byte = bytes(i)
While b <> 0
parity = Not parity
b = b And (b - 1)
End While
Next
Return Convert.ToByte(parity)
End Function

Here is a function that counts bits.
Private Function CountBits(byteArray As Byte()) As Integer
Dim rv As Integer = 0
For x As Integer = 0 To byteArray.Length - 1
Dim b As Byte = byteArray(x)
Dim count As Integer = b
count = ((count >> 1) And &H55) + (count And &H55)
count = ((count >> 2) And &H33) + (count And &H33)
count = ((count >> 4) And &HF) + (count And &HF)
rv += count
Next
Return rv
End Function
Note: this code came from a collection of bit twiddling hacks I found some years ago. I converted it to VB.

Related

Extract specific number from a textboxes

How can I extract from this Textbox, for example what is in parentheses (9,2,8)
Textbox1.Text =
1, 3, 5, 6, 7, 11, 12, 13, 14, 20 (9)
5, 6, 10, 11, 12, 15, 17, 18, 19, 20 (2)
2, 3, 5, 6, 11, 13, 17, 18, 19, 20 (8)
And display in another textbox, Textbox2.Text = 9,2,8
There is another way of doing it.
Imports System.Text.RegularExpressions
Module Module1
Sub Main()
Dim s1 = "1, 3, 5, 6, 7, 11, 12, 13, 14, 20 (9)
5, 6, 10, 11, 12, 15, 17, 18, 19, 20 (2)
2, 3, 5, 6, 11, 13, 17, 18, 19, 20 (8)"
Dim re = New Regex("\(([^)]*)\)")
Dim things = re.Matches(s1)
For Each m As Match In things
Console.WriteLine(m.Groups(1).Value)
Next
Console.ReadLine()
End Sub
End Module
Outputs:
9
2
8
For this regular expression, I think a railroad diagram helps to explain what it does:
From https://regexper.com/#%5C%28%28%5B%5E%29%5D*%29%5C%29
You can achieve your desired result using a simple While loop
<TestMethod()>
Public Sub ExtractNumbersInParentheses()
Dim inputString As String = "1, 3, 5, 6, 7, 11, 12, 13, 14, 20 (9)
5, 6, 10, 11, 12, 15, 17, 18, 19, 20 (2)
2, 3, 5, 6, 11, 13, 17, 18, 19, 20 (8)"
Dim finalResult As String = String.Empty
Dim startingPosition As Integer = inputString.IndexOf("(", 0)
While (startingPosition > 0)
If (finalResult.Length > 0) Then finalResult += ", "
Dim extractedText = inputString.Substring(startingPosition + 1, 1)
finalResult += extractedText
startingPosition = inputString.IndexOf("(", startingPosition + 1)
End While
Debug.Print(finalResult)
End Sub
The key part is the .IndexOf function and each time you query the inputString you move the starting position to be beyond the current position otherwhise you will see the same parenthesis
After I ran this test, the output was:
9, 2, 8

ampl syntax error >>> x[ <<<

I am new to AMPL and can't seem to get past the following syntax error:
set I := {1, 2, 3, 4};
set J := {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
set K := {1, 2, 3, 4, 5, 6};
var d >=0;
var x binary;
CODE.txt, line 18 (offset 332):
syntax error
context: minimize Total_Cost: sum {i in I, j in J, k in K} >>> x[ <<< i,j,k] * d[i];
I can't see why the error seemingly occurs at the square bracket as I thought that subscripts should always be defined within square brackets.
Any tips would be lovely!
Thanks in advance.
After some experimentation, I found my mistake so will share it here in case anyone else encounters the same issue.
I merely forgot to specify the subscripts when initially stating the variable
Find below my modified (working) code:
set I := {1, 2, 3, 4};
set J := {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
set K := {1, 2, 3, 4, 5, 6};
var d{I} >=0;
var x{I,J,K} binary;
minimize Total_Cost: sum {i in I, j in J, k in K} x[i,j,k] * d[i];
When you declare a variable you must to declare his indexes too. In your case the problem is in the "x".
You must write your model like this:
set I := {1, 2, 3, 4};
set J := {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
set K := {1, 2, 3, 4, 5, 6};
var d{i in I} integer >=0;
var x{i in I, j in J, k in K} binary;
Regards!

Assign an integer variable to an integer variable and change name dynamic

Dim LastNumber as Integer = 1
Dim num_0() as Integer = {1, 2, 3, 4, 5}
Dim num_1() as Integer = {6, 7, 8, 9, 10}
Dim num_2() as Integer = {20, 21, 14, 36, 0}
Dim y() As Integer
y(0) = num_0(2)
When I use this code it executes perfectly
But the problem is I want to change the "0" in num_0(2)
When I do...
y(0) = num_ & LastNumber & (2)
This doesnt work
Or
y(0) = ("num_" & LastNumber & "(2)")
This gives me an error that converting a string to an integer is not possible
My question is How can I replace the "0" in num_0(2) with the LastNumber integer variable... so it reads the "8" out of the array num_1(2)
You can use multidimensional array (AKA rectangular array):
Dim num As Integer(,) = { {1, 2, 3, 4, 5}, {6, 7, 8, 9, 10}, {20, 21, 14, 36, 0} }
y(0) = num(LastNumber, 2)
or jagged array (array of arrays) :
Dim num As Integer()() = { ({1, 2, 3, 4, 5}), ({6, 7, 8, 9, 10}), ({20, 21, 14, 36, 0}) }
y(0) = num(LastNumber)(2)

UID Validation - Verhoeff's Algorithm

I am using MS Access & SQL.
I wish to validate 0.1 Mn UID Numbers (Aadhar Cards) for their authenticity.
The UID is based on Verhoeff's Algorithm.
I did find some queries online. They pertained to C++/Java.
Is there a query which validates 0.1 Mn in MS Access for SQL?
As mentioned by Gord Thempson in the comments, you can find the VBA (and many more implementation on the Wikipedia page
For the sake of completeness,
''' <summary>
''' For more information cf. http://en.wikipedia.org/wiki/Verhoeff_algorithm
''' Dihedral Group: http://mathworld.wolfram.com/DihedralGroup.html
''' You can use this code in Excel, Access, etc...
''' </summary>
''' <remarks></remarks>
'The multiplication table
Dim d(0 To 9) As Variant
'The permutation table
Dim p(0 To 8) As Variant
'The inverse table
Dim inv(0 To 9) As Integer
Private Sub initVerhoeffConsts()
If IsArray(d(0)) Then Exit Sub 'Shortcut if already initiated
d(0) = Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
d(1) = Array(1, 2, 3, 4, 0, 6, 7, 8, 9, 5)
d(2) = Array(2, 3, 4, 0, 1, 7, 8, 9, 5, 6)
d(3) = Array(3, 4, 0, 1, 2, 8, 9, 5, 6, 7)
d(4) = Array(4, 0, 1, 2, 3, 9, 5, 6, 7, 8)
d(5) = Array(5, 9, 8, 7, 6, 0, 4, 3, 2, 1)
d(6) = Array(6, 5, 9, 8, 7, 1, 0, 4, 3, 2)
d(7) = Array(7, 6, 5, 9, 8, 2, 1, 0, 4, 3)
d(8) = Array(8, 7, 6, 5, 9, 3, 2, 1, 0, 4)
d(9) = Array(9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
p(0) = Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
p(1) = Array(1, 5, 7, 6, 2, 8, 3, 0, 9, 4)
p(2) = Array(5, 8, 0, 3, 7, 9, 6, 1, 4, 2)
p(3) = Array(8, 9, 1, 6, 0, 4, 3, 5, 2, 7)
p(4) = Array(9, 4, 5, 3, 1, 2, 6, 8, 7, 0)
p(5) = Array(4, 2, 8, 6, 5, 7, 3, 9, 0, 1)
p(6) = Array(2, 7, 9, 3, 8, 0, 6, 4, 1, 5)
p(7) = Array(7, 0, 4, 6, 9, 1, 3, 2, 5, 8)
inv(0) = 0: inv(1) = 4: inv(2) = 3: inv(3) = 2: inv(4) = 1
inv(5) = 5: inv(6) = 6: inv(7) = 7: inv(8) = 8: inv(9) = 9
End Sub
''' <summary>
''' Validates that an entered number is Verhoeff compliant.
''' </summary>
''' <param name="num"></param>
''' <returns>True if Verhoeff compliant, otherwise false</returns>
''' <remarks>Make sure the check digit is the last one!</remarks>
Public Function validateVerhoeff(ByVal num As String) As Boolean
initVerhoeffConsts
Dim c As Integer
Dim i As Integer
c = 0
Dim myArray() As Integer
myArray = StringToReversedIntArray(num)
For i = 0 To UBound(myArray)
c = d(c)(p((i Mod 8))(myArray(i))) 'Version corrected by WHG gives error
Next i
validateVerhoeff = (c = 0)
End Function
''' <summary>
''' For a given number generates a Verhoeff digit
''' </summary>
''' <param name="num"></param>
''' <returns>Verhoeff check digit as Integer</returns>
''' <remarks>Append this check digit to num</remarks>
Public Function generateVerhoeff(ByVal num As String) As Integer
initVerhoeffConsts
Dim c As Integer
Dim i As Integer
c = 0
Dim myArray() As Integer
myArray = StringToReversedIntArray(num)
For i = 0 To UBound(myArray)
c = d(c)(p((i + 1) Mod 8)(myArray(i))) 'Version corrected by WHG gives error in compilation
Next i
generateVerhoeff = inv(c) 'str(inv(c))
End Function
''' <summary>
''' Converts a string to a reversed integer array.
''' </summary>
''' <param name="str"></param>
''' <returns>Reversed integer array</returns>
''' <remarks></remarks>
Private Function StringToReversedIntArray(ByVal str As String) As Integer()
Dim lg As Integer
lg = Len(str)
Dim myArray() As Integer
ReDim myArray(0 To lg - 1)
Dim i As Integer
For i = 0 To lg - 1
myArray(i) = AscW(Mid$(str, lg - i, 1)) - AscW("0")
Next
StringToReversedIntArray = myArray
End Function
''' In Excel don't copy this sub _AssertsVerhoeff()as get a compilation error. 4/21/2013
Public Sub _AssertsVerhoeff()
Debug.Print "Start Verhoeff's Asserts"
Debug.Assert generateVerhoeff("75872") = 2
Debug.Assert validateVerhoeff("758722") = True
Debug.Assert generateVerhoeff("12345") = 1
Debug.Assert validateVerhoeff("123451") = True
Debug.Assert generateVerhoeff("142857") = 0
Debug.Assert validateVerhoeff("1428570") = True
Debug.Assert generateVerhoeff("123456789012") = 0
Debug.Assert validateVerhoeff("1234567890120") = True
Debug.Assert generateVerhoeff("8473643095483728456789") = 2
Debug.Assert validateVerhoeff("84736430954837284567892") = True
Debug.Assert generateVerhoeff("12345") = 1
Debug.Assert validateVerhoeff("123451") = True
Debug.Assert validateVerhoeff("124351") = False
Debug.Assert validateVerhoeff("122451") = False
Debug.Assert validateVerhoeff("128451") = False
Debug.Assert validateVerhoeff("214315") = False
Debug.Print "End Verhoeff's Asserts"
End Sub

How to set an array to a list of values in VB.NET?

I cannot figure out how to set an array to one of two sets of numbers (there will be more later), every way that I have tried throws some kind of error. I have tried to Dim the array inside the case statements, but then I cannot use the array in the For Each, which makes this worthless.... any ideas would be appreciated.
Code:
Dim HourArray() As Integer
Select Case CurrentShapeRow(ROW_PERIOD)
Case "ON", "2X16"
HourArray = {6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21}
Case "2X8", "5X8"
HourArray = {0, 1, 2, 3, 4, 5, 22, 23}
Case Else
Throw New Exception(String.Format("Unhandled Period: {0}", CurrentShapeRow(ROW_PERIOD)))
End Select
For Each HourCount As Integer In HourArray()
'DO SOME STUFF HERE
Next
HourArray = New Integer() {1,2,3,4,5,6,7,8,9}
When you assign an array to an existing variable you must use a constructor explicitly:
HourArray = New Integer() { 6, 7, 8, 9, 10, 11, 12, 13 }
This differs from a declaration and assignment where the constructor is optional:
Dim HourArray() As Integer = { 6, 7, 8, 9, 10, 11, 12, 13 }
Dim hourArray As List(Of Integer)
Select Case CurrentShapeRow(ROW_PERIOD)
Case "ON", "2X16"
hourArray.AddRange(New Integer() {6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21})
Case "2X8", "5X8"
hourArray.AddRange(New Integer() {0, 1, 2, 3, 4, 5, 22, 23})
Case Else
Throw New Exception(String.Format("Unhandled Period: {0}", CurrentShapeRow(ROW_PERIOD)))
End Select
For Each i As Integer In hourArray
Console.WriteLine(i)
Next