Decimal to binary for large number (>2253483438943167) - vb.net

I have a VB.Net application that goes through a series of processes to decode a string, one problem with this is that I have found a function that converts from binary to decimal for any number, but I cannot find a function that will convert a supplied number (in string format) into a binary string. For reference, the binary to decimal conversion function is below:
Public Function baseconv(d As String)
Dim N As Long
Dim Res As Long
For N = Len(d) To 1 Step -1
Res = Res + ((2 ^ (Len(d) - N)) * CLng(Mid(d, N, 1)))
Next N
Return Str(Res)
End Function

What i would do if the number is less than 16*1e18 <-> can hold in a Uint64 :
1) store the number inside an unsigned 64 bits integer : num.
2) then just loop on each bit to test it :
mask = 1<<63
do
if ( num AND mask ) then ->> push("1")
else ->> push("0")
mask = mask >> 1
until mask = 0
(where push builds the output with a string concatenation, or, if performance matters, a StringBuilder, or it can be a stream,... )

what about this?
Module Module1
Sub Main()
Console.WriteLine(Convert.ToString(2253483438943167 * 5, 2))
Console.ReadKey()
End Sub
End Module

Try using the System.Numerics.BigInteger class like this:
Dim d As String
d = "2253483438943167"
Dim bi As BigInteger
bi = BigInteger.Parse(d)
Dim ba() As Byte
ba = bi.ToByteArray()
Dim s As String
Dim N As Long
Dim pad as Char
pad = "0"c
For N = Len(ba) To 1 Step -1
s = s + Convert.ToString(ba(N)).PadLeft(8, pad)
Next N

How about
Dim foo As BigInteger = Long.MaxValue
foo += Long.MaxValue
foo += 2
Dim s As New System.Text.StringBuilder
For Each b As Byte In foo.ToByteArray.Reverse
s.Append(Convert.ToString(b, 2).PadLeft(8, "0"c))
Next
Debug.WriteLine(s.ToString.TrimStart("0"c))
'10000000000000000000000000000000000000000000000000000000000000000

Related

Reversing Digits

I'm trying to make a function that takes a three digit number and reverses it (543 into 345)
I can't take that value from a TextBox because I need it to use the three numbers trick to find a value.
RVal = ReverseDigits(Val)
Diff = Val - RVal
RDiff = ReverseDigits(Diff)
OVal = Diff + RDiff
543-345=198
198+891=1089
Then it puts 1089 in a TextBox
Function ReverseDigits(ByVal Value As Integer) As Integer
' Take input as abc
' Output is (c * 100 + b * 10 + a) = cba
Dim ReturnValue As Boolean = True
Dim Val As String = CStr(InputTextBox.Text)
Dim a As Char = Val(0)
Dim b As Char = Val(1)
Dim c As Char = Val(2)
Value = (c * 100) + (b * 10) + (a)
Return ReturnValue
End Function
I've tried this but can't figure out why it won't work.
You can convert the integer to a string, reverse the string, then convert back to an integer. You may want to enforce the three digit requirement. You can validate the argument before attempting conversion
Public Function ReverseDigits(value As Integer) As Integer
If Not (value > 99 AndAlso value < 1000) Then Throw New ArgumentException("value")
Return Integer.Parse(New String(value.ToString().Reverse().ToArray()))
End Function
My code is pretty simple and will also work for numbers that don't have three digits assuming you remove that validation. To see what's wrong with your code, there are a couple of things. See the commented lines which I changed. The main issue is using Val as a variable name, then trying to index the string like Val(0). Val is a built in function to vb.net and the compiler may interpret Val(0) as a function instead of indexing a string.
Function ReverseDigits(ByVal Value As Integer) As Integer
' Dim ReturnValue As Boolean = True
' Dim Val As String = CStr(InputTextBox.Text)
Dim s As String = CStr(Value)
Dim a As Char = s(0)
Dim b As Char = s(1)
Dim c As Char = s(2)
Value = Val(c) * 100 + Val(b) * 10 + Val(a)
'Return ReturnValue
Return Value
End Function
(Or the reduced version of your function, but I would still not hard-code the indices because it's limiting your function from expanding to more or less than 3 digits)
Public Function ReverseDigits(Value As Integer) As Integer
Dim s = CStr(Value)
Return 100 * Val(s(2)) + 10 * Val(s(1)) + Val(s(0))
End Function
And you could call the function like this
Dim inputString = InputTextBox.Text
Dim inputNumber = Integer.Parse(inputString)
Dim reversedNumber = ReverseDigits(inputNumber)
Bonus: If you really want to use use math to find the reversed number, here is a version which works for any number of digits
Public Function ReverseDigits(value As Integer) As Integer
Dim s = CStr(value)
Dim result As Integer
For i = 0 To Len(s) - 1
result += CInt(Val(s(i)) * (10 ^ i))
Next
Return result
End Function
Here's a method I wrote recently when someone else posted basically the same question elsewhere, probably doing the same homework:
Private Function ReverseNumber(input As Integer) As Integer
Dim output = 0
Do Until input = 0
output = output * 10 + input Mod 10
input = input \ 10
Loop
Return output
End Function
That will work on a number of any length.

Generate unique serial number incrementally

I am writing a vb.net program to generate a three digit serial number I will use in printing a barcode.
The requirements are the counter must count:
001 - 999, A00 - A99, B00 - B99, ..., Z00 - Z99
I cannot use the letters O and I
This code simply increments the value I pass to it by 1. I first check if the value is <=998 and if so return the value in 3 digits. I had to put this in a Try statement because passing the value 'A00' caused an error.
The code is still breaking once I hit Z99.
Problem: If the next serial number = Z90 and the user wants to print 35 barcodes I need to stop the operation before it begins and warn the user there are only 10 avail serial numbers remaining
Also, I am also hoping for advice on how I could have accomplished this in a better manner, any advice would be greatly appreciated
Public Shared Function NextSerial(ByVal value As String) As String
Try
If value <= 998 Then
value += 1
Return ZeroPad(value, 3)
End If
Catch ex As Exception
End Try
Const chars As String = "ABCDEFGHJKLMNPQRSTUVWXYZ"
Dim threenumber As String = ZeroPad(value, 3) 'ensure value is 3 digits.
Dim alpha As String = threenumber.Substring(0, 1).ToUpper() ' 1st digit
Dim beta As String = threenumber.Substring(1, 2) 'remaining two digits
Dim newNumber As String
Dim nextletter As String
If beta = "99" Then
beta = "00"
nextletter = chars.Substring((chars.IndexOf(alpha, System.StringComparison.Ordinal) + 1), 1)
newNumber = nextletter + beta
Return newNumber
Else
beta += 1
newNumber = alpha + ZeroPad(beta, 2)
Return newNumber
End If
End Function
Private Shared Function ZeroPad(ByVal number As String, ByVal toLength As Integer) As String
ZeroPad = number
'add the necessary leading zeroes to build it up to the desired length.
Do Until Len(ZeroPad) >= toLength
ZeroPad = "0" & ZeroPad
Loop
End Function
I think you can do this by assuming your first character is the 'hundreds' and converting to a number and incrementing:
Private Function NextSerial(value As String) As String
Const chars As String = "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ"
Dim numericValue As Integer = 100 * (chars.IndexOf(value.Substring(0, 1))) + Integer.Parse(value.Substring(1, 2))
numericValue += 1
Return chars.Substring(numericValue \ 100, 1) + (numericValue Mod 100).ToString.PadLeft(2, "0")
End Function
You should of course perform some error checking at the start of the function to make sure a valid serial number has been handed into the function. I would also put this function into a class and add functions such as isValid, SerialsRemaining and perhaps a function to retrieve a list of multiple serials.
I created constant strings that represent every available character in each digit position. I then used indexing to lookup the positions of the current serial number & moved one number forward to get the next serial. This will always provide the next serial until you run out of numbers.
Note: this code can easily be made more compact, but I left it as-is thinking it might be clearer.
Const charString1 As String = "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ"
Const charString2 As String = "0123456789"
Const charString3 As String = "0123456789"
Public Function NextSerial(ByVal value As String) As String
' ensures the input is three chars long
Dim threenumber As String = Right("000" & value, 3)
Dim char1 As String = threenumber.Substring(0, 1)
Dim char2 As String = threenumber.Substring(1, 1)
Dim char3 As String = threenumber.Substring(2, 1)
Dim char1Pos As Integer = charString1.IndexOf(char1)
Dim char2Pos As Integer = charString2.IndexOf(char2)
Dim char3Pos As Integer = charString3.IndexOf(char3)
If char1Pos = -1 Or char2Pos = -1 Or char3Pos = -1 Then Throw New Exception("Invalid serial number format")
' move to next serial number
char3Pos += 1
If char3Pos > charString3.Length() - 1 Then
char3Pos = 0
char2Pos += 1
End If
If char2Pos > charString2.Length() - 1 Then
char2Pos = 0
char1Pos += 1
End If
If char1Pos > charString1.Length() - 1 Then Throw New Exception("Out of serial numbers!")
Return charString1.Substring(char1Pos, 1) & charString2.Substring(char2Pos, 1) & charString3.Substring(char3Pos, 1)
End Function
I suggest you use integer for all your check and calculation and only convert to serial number for display. It'll be a lot easier to know how many serial number are remaining.
Your serial number is similar to integer except everything over 100 is a letter instead of a number.
Note: It's very important to add error checking, this assumes that all input are valid.
Module Module1
Sub Main()
Console.WriteLine(SerialNumber.ConvertSerialNumberToInteger("D22"))
Console.WriteLine(SerialNumber.ConvertIntegerToSerialNumber(322))
Console.WriteLine(SerialNumber.GetAvailableSerialNumber("Z90"))
For Each sn As String In SerialNumber.GetNextSerialNumber("X97", 5)
Console.WriteLine(sn)
Next
Console.ReadLine()
End Sub
End Module
Class SerialNumber
Private Const _firstPart As String = "ABCDEFGHJKLMNPQRSTUVWXYZ"
Public Shared Function ConvertSerialNumberToInteger(ByVal serialNumber As String) As Integer
Return (_firstPart.IndexOf(serialNumber(0)) * 100) + Integer.Parse(serialNumber.Substring(1, 2))
End Function
Public Shared Function ConvertIntegerToSerialNumber(ByVal value As Integer) As String
Return _firstPart(value \ 100) & (value Mod 100).ToString("00")
End Function
Public Shared Function GetAvailableSerialNumber(ByVal serialNumber As String)
Dim currentPosition As Integer
Dim lastPosition As Integer
currentPosition = ConvertSerialNumberToInteger(serialNumber)
lastPosition = ConvertSerialNumberToInteger("Z99")
Return lastPosition - currentPosition
End Function
Public Shared Function GetNextSerialNumber(ByVal serialNumber As String, ByVal amount As Integer) As List(Of String)
Dim newSerialNumbers As New List(Of String)
Dim currentPosition As Integer
currentPosition = ConvertSerialNumberToInteger(serialNumber)
For i As Integer = 1 To amount
newSerialNumbers.Add(ConvertIntegerToSerialNumber(currentPosition + i))
Next
Return newSerialNumbers
End Function
End Class

example for VB.NET to calculate CRC16 of an string or Byte Array

With reference to this link
Calculate CRC32 of an String or Byte Array
I modified the code in order to calculate the CRC16 instead of CRC32, however I am getting wrong result, can some one point me where is the mistake?
Private Sub Main()
Crc16.ComputeChecksum(Encoding.UTF8.GetBytes("Some string"))
End Sub
Public Class CRC16
Shared table As UShort()
Shared Sub New()
Dim poly As UShort = &HA001US 'calculates CRC-16 using A001 polynomial (modbus)
table = New UShort(255) {}
Dim temp As UShort = 0
For i As UShort = 0 To table.Length - 1
temp = i
For j As Integer = 8 To 1 Step -1
If (temp And 1) = 1 Then
temp = CUShort((temp >> 1) Xor poly)
Else
temp >>= 1
End If
Next
table(i) = temp
Next
End Sub
Public Shared Function ComputeChecksum(ByVal bytes As Byte()) As UShort
Dim crc As UShort = &H0US ' The calculation start with 0x00
For i As Integer = 0 To bytes.Length - 1
Dim index As Byte = CByte(((crc) And &HFF) Xor bytes(i))
crc = CUShort((crc >> 8) Xor table(index))
Next
Return Not crc
End Function
End Class
Try this, it's working VB6 code for Instrument control. (sCommand is a temp string which contains all Bytes, Result is added to sCommand, Modbus is using LSB first, TextToString and StringToAscii are functions to convert a readable string "FF EE" into ASCII and back, thus they are not of interest here.):
Private Sub cmdCRC16_Click()
Dim sCommand As String
Dim x As Long
Dim y As Long
Dim lCRC As Long
sCommand = TextToString(txtASCII)
'Initial value
lCRC = 65535 '(&HFFFF results in Integer -1)
For x = 1 To Len(sCommand)
lCRC = lCRC Xor Asc(Mid(sCommand, x, 1))
For y = 1 To 8
If (lCRC Mod 2) > 0 Then
lCRC = (lCRC And 65534) / 2
lCRC = lCRC Xor 40961 '(&HA001 results in whatever negative integer)
Else
lCRC = (lCRC And 65534) / 2
End If
Next y
Next x
'Add CRC with LSB first
sCommand = sCommand + Chr(lCRC And 255)
sCommand = sCommand + Chr((lCRC And 65280) / 256)
txtASCII = StringToASCII(sCommand)
End Sub
I just came accross the same issue. Simple solution is to omit negation at the end, so just change your "Return Not crc" to "Return crc" and you be fine.
There are various variants of CRC-16, where "CRC-16" normally refers to the IBM variant, also called "ARC". It uses an XorOut value of zero. See Catalogue of parametrised CRC algorithms with 16 bits.

How to represent a number in the form of A*10-^n?

I recently wrote this program in Visul Basic 13.
it searchs for the nth catalan number but after 48 even Decimal type is too short.
Is there any other way to represent them? like in the form of A*10^n?
Public Class Try_Catalan_Number
'Catalan numbers form a sequence of natural numbers that occur in various counting problems,
'often involving recursively defined objects.
Inherits Base_Number
Public Overrides Sub Test()
Dim Return_Catalan_Value As Decimal
If Function_Catalan(Return_Catalan_Value) = False Then
Return_To_Form_Boolean = False
Else
Return_To_Form_Boolean = True
End If
Return_To_Form_Value = Function_Catalan(Return_Catalan_Value)
End Sub
Private Function Function_Catalan(Return_Catalan_Value As Decimal) As Decimal
'We return a Decimal function because catalan numbers can be very big and decimal is the biggest type.
Dim Binomial_Cofficients As Decimal
Dim Result As Decimal
Dim Number_Of_Loops As Integer
Dim tmpNumber As Object
Dim K As Decimal
Dim N As Decimal
If (Number > 48) Then
Return False
Exit Function
End If
'48 is the largest catalan number position which can be displayed...any position above 48 is too big.
tmpNumber = Number - 1
N = 2 * tmpNumber
K = tmpNumber
Result = 1
For Number_Of_Loops = 1 To K
Result = Result * (N - (K - Number_Of_Loops))
Result = Result / Number_Of_Loops
Next Number_Of_Loops
Binomial_Cofficients = Result
tmpNumber = Number - 1
tmpNumber = ((1 / (1 + tmpNumber)) * Binomial_Cofficients)
Return_Catalan_Value = tmpNumber
Return Return_Catalan_Value
End Function
End Class
[I assume by "Visul Basic 13" you mean the VB which is associated with Visual Studio 2013, i.e. VB version 12.0.]
You can use System.Numerics.BigInteger (you'll have to add a reference to System.Numerics):
Imports System.Numerics
Module Module1
Friend Function Factorial(n As Integer) As BigInteger
If n < 2 Then Return 1
If n = 2 Then Return 2
Dim f As BigInteger = BigInteger.Parse("2")
For i = 3 To n
f *= i
Next
Return f
End Function
Friend Function CatalanNumber(n As Integer) As BigInteger
Return Factorial(2 * n) / (Factorial(n + 1) * Factorial(n))
End Function
Sub Main()
For i = 0 To 550
Console.WriteLine(CatalanNumber(i).ToString())
Next
Console.ReadLine()
End Sub
End Module
I did not test to see the maximum Catalan number it can calculate, and I have no inclination to verify the results beyond those shown on the Wikipedia page.
Optimisations are left as an exercise for the reader ;)
Edit: FWIW, I can get it to run a bit faster by using
Function CatalanNumber(n As Integer) As BigInteger
Dim nFactorial = Factorial(n)
Dim twonFactorial = nFactorial
For i = (n + 1) To 2 * n
twonFactorial = BigInteger.Multiply(twonFactorial, i)
Next
Return twonFactorial / (BigInteger.Pow(nFactorial, 2) * (n + 1))
End Function
The speed increase varies from roughly 50% (n=50) to 20% (n=5000). If you're only using the function a few times for fairly small n, there may be little point worrying about it.
Edit2 Re-writing your function a bit to make it easier to read and removing the off-by-one error, we get:
Private Function Function_Catalan(a As Integer) As BigInteger
If a = 0 Then Return 1
Dim binomialCofficient As BigInteger = BigInteger.One
Dim n As Integer = 2 * a
Dim k As Integer = a - 1
For i As Integer = 1 To k
binomialCofficient = binomialCofficient * (n - (k - i)) / i
Next i
Return binomialCofficient / a
End Function
to get this format you could use:
String.Format("{0:E4}", InputNumber)

Is there a way to force circular integer overflow in Excel VBA?

I'm trying to convert some Java code to Excel and the required hashcode function generates an overflow error, instead of wrapping to the negative
Function FnGetStringHashCode(ByVal str As String) As Integer
Dim result, i
FnGetStringHashCode = 17
For i = 1 To Len(str)
Dim c, a
c = Mid(str, i, 1)
a = AscW(c)
FnGetStringHashCode = 31 * FnGetStringHashCode + a
Next i
End Function
Is there a way of doing this in Excel VBA?
Although there is no built-in way to do this, the computation is simple:
Public Function coerceLongToInt(toCoerce As Long) As Integer
Const MIN_INT As Long = -32768
Const MAX_INT As Long = 32767
Const NUM_INTS As Long = MAX_INT - MIN_INT + 1
Dim remainder As Long
remainder = toCoerce Mod NUM_INTS
If remainder > MAX_INT Then
coerceLongToInt = remainder - NUM_INTS
ElseIf remainder < MIN_INT Then
coerceLongToInt = remainder + NUM_INTS
Else
coerceLongToInt = remainder
End If
End Function
This is the behavior you want, right?
?coerceLongToInt(-32769)
32767
?coerceLongToInt(-32768)
-32768
?coerceLongToInt(-1)
-1
?coerceLongToInt(0)
0
?coerceLongToInt(1)
1
?coerceLongToInt(32767)
32767
?coerceLongToInt(32768)
-32768
You would use it like this:
Function FnGetStringHashCode(ByVal str As String) As Integer
Dim result, i
FnGetStringHashCode = 17
For i = 1 To Len(str)
Dim c, a
c = Mid(str, i, 1)
a = AscW(c)
FnGetStringHashCode = coerceLongToInt(31 * CLng(FnGetStringHashCode) + a)
Next i
End Function
You need the 'CLng' call in there to prevent VBA from raising an overflow error when it computes the intermediate value (31 * [some integer >= 1058]).
I have modified a little the script of ours. The main difference is returning type of your function. Now it returns Variant. As decimal is a subset of Variant, and it can store bigger numbers than long I think it is a good solution (see VBA data types) - I do not know is it possible to explicitly return Decimal. Here is the script
Function FnGetStringHashCode(ByVal str As String) As Variant
Dim tmp As Variant, c As String, a As Integer, i As Integer
tmp = 17
For i = 1 To Len(str)
c = Mid$(str, i, 1)
a = AscW(c)
tmp = 31 * tmp + a
Next i
FnGetStringHashCode = tmp
End Function
And a little test routine
Sub test()
Debug.Print CStr(FnGetStringHashCode("dawdaedae"))
End Sub