I would like to generate a sequence of strings in the same format of digits and letters positions
e.g ABC12,DEV45,UED23,...
It's also required a formula to generate the next string from the current one. for example from the string above:
f(ABC12)=DEV45
f(DEV45)=UED23
I would like to use this to generate next "look-random" unique code in a defined format. What algorithm do you suggest? Thanks a lot.
A code of the format "ABC12" is basically a 5-digit number where the first 3 digits are base-26 and the last 2 digits are decimal. There are 26×26×26×10×10 or 1,757,600 of these. Each code is easily converted to the corresponding number and back:
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
ABC12 = ((( 0 * 26 + 1) * 26 + 2) * 10 + 1) * 10 + 2 = 2,812
DEV45 = ((( 3 * 26 + 4) * 26 + 21) * 10 + 4) * 10 + 5 = 215,345
UED23 = (((20 * 26 + 4) * 26 + 3) * 10 + 2) * 10 + 3 = 1,362,723
2,812 / 10 = 281 rem: 2
281 / 10 = 28 rem: 1
28 / 26 = 1 rem: 2
1 / 26 = 0 rem: 1
0 / 26 = 0 rem: 0 -> 0 1 2 1 2 -> ABC12
215,345 / 10 = 21,534 rem: 5
21,534 / 10 = 2,153 rem: 4
2,153 / 26 = 82 rem: 21
82 / 26 = 3 rem: 4
3 / 26 = 0 rem: 3 -> 3 4 21 4 5 -> DEV45
1,362,723 / 10 = 136,272 rem: 3
136,272 / 10 = 13,627 rem: 2
13,627 / 26 = 524 rem: 3
524 / 26 = 20 rem: 4
20 / 26 = 0 rem: 20 -> 20 4 3 2 3 -> UED23
To loop through the numbers from 0 to 1,757,599 in a pseudo-random way, choose a step size which only returns to zero after having gone through every number, and then calculate the next value as:
x -> (x + step) % 1,757,600
So step should have no common factors with 1,757,600:
1,757,600 = 2 * 2 * 2 * 2 * 2 * 5 * 5 * 13 * 13 * 13
and preferably be greater than 26*26*10*10 so that every digit changes with every step; so, e.g.:
step = 3^11 = 177,147
which gives this sequence:
2,812 ABC12
( 2,812 + 177,147) % 1,757,600 = 179,959 -> CRF59
(179,959 + 177,147) % 1,757,600 = 357,106 -> FHJ06
...
Here's a code example to demonstrate the method. It's a bit fiddly because JavaScript. In C-like languages where a string is basically an array of integers, the code will be more straightforward.
function nextCode(current) {
var base = [26,26,26,10,10], symbol = [65,65,65,48,48], char = [], number = 0;
for (var i = 0; i < 5; i++) {
var digit = current.charCodeAt(i) - symbol[i];
number = number * base[i] + digit;
}
number = (number + 177147) % 1757600;
for (var i = 4; i >= 0; i--) {
var remainder = number % base[i];
number = (number - remainder) / base[i];
char[i] = String.fromCharCode(symbol[i] + remainder);
}
return char.join('');
}
document.write("ABC12 → " + nextCode("ABC12"));
One of the approaches is to precalculate letter part in an array form and then combine it with the consecutive numbers. For the letter array:
start with AAA, AAB, AAC, ..., ABA, ABB, ..., ZZZ (total 17576 elements) -- all possible unique combinations;
shuffle the array -- now they are in (a) random and (b) predictive order;
from any given value -> use the next element from the array.
For the digit part, use simple counting:
start with 00;
from any given value -> increment by 1;
if the result is 100, use the next letter part -- thus each string is unique.
This provides 1757600 unique strings like ABC12.
Related
Could someone explain the code? I just can not understand why this code gives output like this:
1
3
6
10
15
21
I expected the code to give something like this:
1
3
5
7
9
11
What am I missing here?
def tri_recursion(k):
if(k > 0):
result = k + tri_recursion(k-1)
print(result)
else:
result = 0
return result
tri_recursion(6)
For your recursive function, the termination condition is k=0.
It's clear that if k=0, tri_recursion(0) = 0.
If k=1, tri_recursion(1) = 1 + tri_recursion(0), which from above, is 1 + 0 or 1.
If k=2, tri_recursion(2) = 2 + tri_recursion(1), which from above, is 2 + 1 or 3.
If k=3, tri_recursion(3) = 3 + tri_recursion(2), which from above, is 3 + 3 or 6.
If k=4, tri_recursion(4) = 5 + tri_recursion(3), which from above, is 4 + 6 or 10.
If k=5, tri_recursion(5) = 4 + tri_recursion(4), which from above, is 5 + 10 or 15.
If k=6, tri_recursion(6) = 6 + tri_recursion(5), which from above, is 6 + 15 or 21.
See the pattern?
Your code is calculating the sum of numbers up to n where n is 6 in the above case. The print statement prints the intermediate results. Hence the output 1 3 6 10 15 21.
1 - The sum of numbers from 0 to 1
3 - The sum of numbers from 0 to 2
6 - The sum of numbers from 0 to 3
10 - The sum of numbers from 0 to 4
15 - The sum of numbers from 0 to 5
21 - The sum of numbers from 0 to 6
The sequence look like this 112123123412345...
If the input is 55,it should return 1,not 10. And if the input is 56,it should return 0,not 1. You got the idea.
So we have a sequence composed of the composition of
1 1 digit 1 digit total
12 2 digits 3 digits total
123 3 digits 3*(3+1)/2 = 6 digits total
1234 4 digits 4*(4+1)/2 = 10 digits total
...
123..89 9 digits 9*(9+1)/2 = 45 digits total
123..8910 11 digits 10*(10+1)/2 + 1 = 56
123..891011 13 digits 11*(10+1)/2 + 3 = 69
123..89101112 15 digits 12*(12+1)/2 + 3*(3+1)/2 = 84 digits
This is OEIS Sequence A165145 and also see the related sequence OEIS A058183.
A formula for the total number of digits is
f(n) = n*(n+1)/2 + {(n-9)*(n-8)/2 : if n>=10} + {(n-99)*(n-98)/2 : if n>=100) + ...
Some key points f(9) = 45, f(99) = 99*100/2 + 90*91/2 = 9045, f(999) = 1,395,495.
An outline algorithm for finding the k-th digit would be
Find which part of the sequence you are in n<=9, 10 <= n <= 99, 100 <= n <= 999 by comparing k with the boundary values 45, 9045, 1395495.
Recover the value of n
Find the actual digit which will be k-f(n) along sequence for the n-th number.
If we take 10 <= n <= 99 the formula for the number of digits is
n*(n+1)/2 + (n-9)*(n-8)/2
= 1/2( n^2 + n + n^2 - 17 n + 72)
= n^2 - 8 n + 36
So given 45 < k <= 9045 we solve k = n^2 - 8 n + 36, using the quadratic formula
n = ceil( ( 8 + sqrt(64 - 4 (36 - k)))/2)
We need a different quadratic formula for k outside the range.
For example take k = 100, using the formula gives n=13. There are f(12)=84 digits for all the numbers upto 12, so the first digit of the 13th string is at position 85. So we are looking for the 16th digit. We can use the formula
digit(l) := l <= 9 ? l : (l%2==0 ? floor((l+10)/20) : ((l-11)/2)%10 )
to find the actual digit, which is 1.
I have a set of "Points" & it's "Value".
I want to get highest possible "Value" from combination of "Points".
Example:
My Target Point: 100
Point Value
1 111
2 222
3 333
4 444
5 555
6 666
7 777
8 888
9 999
10 1110
11 1221
12 1332
13 1443
14 1554
15 1665
16 1776
17 1887
18 1998
19 2109
20 2220
There can be TRILLIONS of combination but I need only those combinations upto "My Target Point" yielding Highest "Value".
Possible Answers:
1. (Point 16)*2 + (Point 17)*4 = 100
(Value 1776)*2 + (Value 1887)*4 = 11100
2. (Point 1)*100 = 100
(Value 111)*100 = 11100
& so on.....
So finally I need just one (any) combination with highest value.
amt2 = 0
For i20 = 0 To 5 ' (Max multiple -> 100/20 = 5)
For i19 = 0 To 5 ' (Max multiple -> 100/19 = 5)
For i18 = 0 To 5
For i17 = 0 To 5
For i16 = 0 To 6
For i15 = 0 To 6
For i14 = 0 To 7
For i13 = 0 To 7
For i12 = 0 To 8
For i11 = 0 To 9
For i10 = 0 To 10
For i9 = 0 To 11
For i8 = 0 To 12
For i7 = 0 To 14
For i6 = 0 To 16
For i5 = 0 To 20
For i4 = 0 To 25
For i3 = 0 To 33
For i2 = 0 To 50
For i1 = 0 To 100 ' (Max multiple -> 100/1 = 1)
point1 = (1 * i1) + (2 * i2) + (3 * i3) + (4 * i4) + (5 * i5) + (6 * i6) + (7 * i7) + (8 * i8) + (9 * i9) + (10 * i10) + (11 * i11) + (12 * i12) + (13 * i13) + (14 * i14) + (15 * i15) + (16 * i16) + (17 * i17) + (18 * i18) + (19 * i19) + (20 * i20))
If point1 <= 100 Then
amt1 = (111 * i1) + (222 * i2) + (333 * i3) + (444 * i4) + (555 * i5) + (666 * i6) + (777 * i7) + (888 * i8) + (999 * i9) + (1110 * i1 + (1221 * i11) + (1332 * i12) + (1443 * i13) + (1554 * i14) + (1665 * i15) + (1776 * i16) + (1887 * i17) + (1998 * i18) + (2109 * i19) + (2220 * i20)
If amt2 < amt1 Then
amt2 = amt1
<Save Combination Details>
End If
End If
Next i1
Next i2
Next i3
Next i4
Next i5
Next i6
Next i7
Next i8
Next i9
Next i10
Next i11
Next i12
Next i13
Next i14
Next i15
Next i16
Next i17
Next i18
Next i19
Next i20
Problem with my code is that it iterates through ALL possible combinations which takes lots of time & produce little result.
"Trillions" underestimates how much work your code is trying to do. Your code would pass through the innermost loop 1.94*10^21 times, which at the rate of 10 million passes per second (about the most VBA could give) would take over 6 million years. Instead, just use the Solver add-in to solve what is a fairly straightforward integer programming problem.
Set up your spreadsheet something like this:
Your data is in columns A:B, I added a new column of decision variables, a constraint cell in D2, and an objective function in E2.
The formula in D2 is:
=SUMPRODUCT(A2:A21,C2:C21)
and in E2 it is:
=SUMPRODUCT(B2:B21,C2:C21)
Then I simply ask the solver to find the maximum of cell E2 by changing cells C2:C21 subject to the two constraints that D2 <= 100 and that C2:C21 are integers. I keep the default setting that variables are assumed to be nonnegative, and tell the solver to use the Simplex method (which under the hood will use branch-and-bound for solving this ILP). The optimal solution according to the Solver (found in less than a second as opposed to 6 million years) is 10*Point1 + 6*Point15 with a total value of 11100 -- which happens to be a value that you have already found, showing that this problem has multiple optima.
It is possible but not easy to do this all in VBA, since the solver add-in can be invoked in code. See this for a basic introduction.
Here is the code to convert a decimal number number to binary (DectoBin), and to print a list of all binary numbers from 1 to number (print_formatted) :
def DectoBin(number):
j=1
binary = 0
while (number != 0):
reminder = number % 2
number= int(number / 2)
binary= binary + reminder * j
j *= 10
return(binary)
def print_formatted(number):
for j in range(1, number + 1):
bin1 = DectoBin(j)
print(bin1, end='\n')
Output I get :
1
10
11
100
101
110
111
1111
Output I want (right-justified list of binary numbers) :
1
10
11
100
101
110
111
1000
See PEP 498 which introduces Literal String Interpolation. You can use it to right justify your print out:
def DectoBin(number):
j=1
binary = 0
while (number != 0):
reminder = number % 2
number= int(number / 2)
binary= binary + reminder * j
j *= 10
return(binary)
for i in range(16):
print (f'{DectoBin(i):>5}')
which produces the following output:
0
1
10
11
100
101
110
111
1000
1001
1010
1011
1100
1101
1110
Define print_formatted function as following. This ensures that the binary numbers are correctly right justified with the right number of spaces before each number :
import math
def print_formatted(number):
max_bits = math.ceil(math.log2(number + 1))
for j in range(1, number + 1):
bin1 = str(DectoBin(j)).rjust(max_bits)
print(bin1, end='\n')
max_bits is the number of bits used to represent number, and rjust is used to right justify the string in a string of length max_bits.
I have a really long truth table and the binary column is showing up like this:
A + B = S BINARY
0 + 0 = 0 0
0 + 1 = 1 1
0 + 2 = 2 10
0 + 3 = 3 11
0 + 4 = 4 100
0 + 5 = 5 101
0 + 6 = 6 110
0 + 7 = 7 111
0 + 8 = 8 1000
0 + 9 = 9 1001
0 + 10 = 10 1010
0 + 11 = 11 1011
0 + 12 = 12 1100
0 + 13 = 13 1101
0 + 14 = 14 1110
0 + 15 = 15 1111
Where the BINARY column =DEC2BIN(S)
I need to force the Binary values to have 4 digits all the time. So 0 = 0000, 3 = 0011, etc. How do I do this in excel?
Solution:
=DEC2BIN(S,6)
Rather than filling column S with:
=A1 + B1
to see 1 thru 15, use:
=DEC2BIN(A1+B1,4) to keep the leading zeros in 4-digit-binary format.
Highlight binary cells
Right-click, select "Format Cells..."
Number tab, select "Custom"
Enter 0000 into the Type text box.
Click OK.
Another, not the best way, but should work:
=RIGHT("0000"&DEC2BIN(S),4)
The above solution is correct
=DEC2BIN(A1,4)
This will show cell A1 in binary 4 digit format regardless of the value .
In the Spanish Excel version you use a semi colon like so .
=DEC.A.BIN(J6;7)