how to map a specialized string into specified integer - c++

I am doing some financial trading work. I have a set of stock symbols but they have very clear pattern:
it's composed of two characters AB, AC AD and current month which is a four digit number: 1503, 1504, 1505. Some examples are:
AB1504
AB1505
AC1504
AC1505
AD1504
AD1505
....
Since these strings are so well designed patterned, I want to map (hash) each of the string into a unique integer so that I can use the integer as the array index for fast accessing, since I have a lot of retrievals inside my system and std::unordered_map or any other hash map are not fast enough. I have tests showing that general hash map are hundred-nanoseconds latency level while array indexing is always under 100 nanos.
my ideal case would be, for example, AB1504 maps to integer 1, AB1505
maps to 2...., then I can create an array inside to access the information related to these symbols much faster.
I'm trying to figure out some hash algorithms or other methods that can achieve my goal but couldn't find out.
Do you guys have any suggestions on this problem?

You can regard the string as a variable-base number representation, and convert that to an integer. For example:
AC1504:
A (range: A-Z)
C (range: A-Z)
15 (range: 0-99)
04 (range: 1-12)
Extract the parts; then a hash function could be
int part1, part2, part3, part4;
...
part1 -= 'A';
part2 -= 'A';
part4 -= 1;
return (((part1 * 26 + part2) * 100 + part3) * 12 + part4;

The following values should be representable by a 32-bit integer:
XYnnnn => (26 * X + Y) * 10000 + nnnn
Here X and Y take values in the range [0, 26), and n takes values in the range [0, 10).
You have a total of 6,760,000 representable values, so if you only want to associate a small amount of data with it (e.g. a count or a pointer), you can just make a flat array, where each symbol occupies one array entry.

If you parse the string as a mixed base number, first 2 base-26 digits and then 4 base-10 digits you will quickly get a unique index for each string. The only issue is that if you might get a sparsely populated array.
You can always reorder the digits when calculating the index to minimize the issue mentioned above.
As the numbers are actually months I would calculate the number of months from the first entry and multiply that with the 2 digit base-26 number from the prefix.
Hope you can make some sense from this, typing on my tablet at the moment. :D

I assume the format is 'AAyymm', where A is an uppercase character yy a two digit year and mm the two digit month.
Hence you can map it to 10 (AA) + Y (yy) + 4 (mm) bits. where Y = 32 - 10 - 4 = 18 bits for a 32 bit representation (or 262144 years).
Having that, you can represent the format as an integer by shifting the characters to there place and shifting the year and month pairs to there places after converting these to an integer.
Note: There will always be gaps in the binary representation, Here the 5+5 bit representation for the characters (6 + 6 values) and in the 4 bit month representation (4 values)
To avoid the gaps change the representation to ABmmmm, were the pair AB is represented by a the number 26*A+B and mmmm is the month relative to some zero month in some year (which covers 2^32/1024/12 = 349525 years - having 32 bits).
However, you might consider a split of stock symbols and time. Combining two values in one field is usually troublesome (It might be a good storage format, but no good 'program data format').

Related

Output division result including digits after decimal - Qt

I am sorry if it's already answered in here, but I couldn't find the exact solution I am looking for.
I am trying to output the result of a division of two variable which is continuously changing. The result may vary from 0.00 to 100.12314235234523 (not exactly this specific, I just wanted to give you an idea). I want to print the result only 2 digits after the decimal point, if there is nothing after decimal, it should print 2 zeroes after decimal.
For example:
10 / 5 = 2.00
23 / 6 = 3.83
I don't need to round up the result for example, if the output is: 73.4869999, I don't need it to be 73.49, 73.48 is fine with me.
What I have written so far is:
packet_loss[2]->setText(QString("%1%2%3").arg(((data.packet_loss_tx) * 100) / data.packets_tx).
arg(locale.decimalPoint()).
arg((((data.packet_loss_tx) * 100) % data.packets_tx), 2, 10, QChar('0')));
But this prints all the values after the decimal point. I can divide this part arg((((data.packet_loss_tx) * 100) % data.packets_tx) with 10, 100 or 1000 to reduce the number of decimals after the decimal point but this is a variable which changes every seconds. So if the output is 3 digits after decimal and I divide it by 10, I will get proper output, but the next value may be 5 digits after decimal and division by 10 will give me 4 digits after decimal. I want the final output to show only 2 digits after decimal.
You could try to use QString::number() function with specific formatting options (two digits precision). For example:
auto s = QString::number(100.12914235234523, 'f', 2); // Gives "100.13"
Besides, if you use floating point numbers, it's better to multiply them with floating point numbers too. I.e. you need to perform your calculations using 100.0 instead of integer value 100.

How does one use the format() method in python to pad numbers after the E exponent with zeros?

I have managed to almost get my number output formatted to exactly what I need after reading some documentation on .format, and developing this code:
timepoint = 6
strTimepoint = "{:1.7E}".format(timepoint)
whereby printing strTimepoint will issue this:
# with timepoint = 6
>>6.0000000E+00
# with timepoint = 12
>>1.2000000E+01
and so on.
The only thing I need to do to make this the string I need is for the exponent digits to be padded with zeros to be three digits, hence:
# timepoint = 6
>>6.0000000E+000
# timepoint = 12
>>1.2000000E+001
I cannot simply pad with a zero after the fact, as it needs to be adaptive to numbers requiring higher than single digit exponents.
I was not able to find documentation on this, so any help on this topic is of help, thank you.
It appears that it's just not possible with single str.format call.
It won't be as pretty, but you can simply add another one:
# Regular Python's scientific notation, split up to coefficient and exponent.
x, e = "{:1.7E}".format(timepoint).split("E")
# Format again: coefficient first, then sign, then padded "sign-less" exponent.
strTimepoint = "{}E{}{:0>3}".format(x, e[0], e[1:])
Wrapping it all in a function is, of course, strongly encouraged (adjust the name to your needs):
def foo(timepoint):
# Regular Python's scientific notation, split up to coefficient and
# exponent.
x, e = "{:1.7E}".format(timepoint).split("E")
# Format again: coefficient first, then sign, then padded "sign-less"
# exponent.
return "{}E{}{:0>3}".format(x, e[0], e[1:])
foo(6) # '6.0000000E+000'
foo(12) # '1.2000000E+001'
foo(1e123) # '1.0000000E+123'
You could insert the 0 after the fact with re.sub, but it would have the effect of lengthening the string by one character in the case that the substitution occurs:
>>> re.compile("(E[-+])(\d\d)$").sub(r'\g<1>0\2',"{:7.1E}".format(6E19))
'6.0E+019'
With the 7.1 format, that's not a problem because if the exponent had three digits, the minimum field length would be 8:
>>> re.compile("(E[-+])(\d\d)$").sub(r'\g<1>0\2',"{:7.1E}".format(6E190))
'6.0E+190'
But in general, it could produce misalignments.
(Of course, in real code, you'd only compile that regex once, rather than every time you do the conversion.)

Answering Queries on Binary array

Given a binary array of length <=10^5 and almost equal number of queries. Each query is given by two integers (l,r) for each query we have to computer the total number of consecutive 0's and 1's in the range [l,r].
If n is the length of the array then 1 <= l < r <= n.
For example:
if the binary array (1-indexed) is "011000" and say there are 5 queries:
1 3
5 6
1 5
3 6
3 4
Then the required answer is
1
1
2
2
0
I am aware that this can be solved by a linear time (worst case) algorithm for each query but due to the large number of queries it's not feasible.
Just wondering which is the most efficient way to achieve this?
You can do it with O(n) space complexity and O(log(n)) search time for each query. Calculate the counts for windows of size 1, 2, 4, .... For a given query you can find O(log(n)) windows (at most 2 windows of a particular size), summing which you can find your answer.
As Dukeling said in the comments, you can preprocess in O(n) to compute an array B where B[x] contains the total number of consecutive digits seen in [1..r].
This allows a query in O(1) to find the number of consecutive digits in the range [l,r] by using the array to count the total number in the range [1,r] and subtracting the number in the range [1,l].
Python code:
def preprocess(A):
last=A[0]
B=[0,0]
num_consecutive=0
for a in A[1:]:
if a==last:
num_consecutive+=1
B.append(num_consecutive)
last=a
return B
def query(B,l,r):
return B[r]-B[l]
A=[0,1,1,0,0,0]
B=preprocess(A)
print query(B,1,3)
print query(B,5,6)
print query(B,1,5)
print query(B,3,6)
print query(B,3,4)

Adding one digit (0-9) to the sequence/string creates new 4 digits number

I'm trying to find an algorithm which "breaks the safe" by typing the keys 0-9. The code is 4 digits long. The safe will be open where it identifies the code as substring of the typing. meaning, if the code is "3456" so the next typing will open the safe: "123456". (It just means that the safe is not restarting every 4 keys input).
Is there an algorithm which every time it add one digit to the sequence, it creates new 4 digits number (new combinations of the last 4 digits of the sequence\string)?
thanks, km.
Editing (I post it years ago):
The question is how to make sure that every time I set an input (one digit) to the safe, I generate a new 4 digit code that was not generated before. For example, if the safe gets binary code with 3 digits long then this should be my input sequence:
0001011100
Because for every input I get a new code (3 digit long) that was not generated before:
000 -> 000
1 -> 001
0 -> 010
1 -> 101
1 -> 011
1 -> 111
0 -> 110
0 -> 100
I found a reduction to your problem:
Lets define directed graph G = (V,E) in the following way:
V = {all possible combinations of the code}.
E = {< u,v > | v can be obtained from u by adding 1 digit (at the end), and delete the first digit}.
|V| = 10^4.
Din and Dout of every vertex equal to 10 => |E| = 10^5.
You need to prove that there is Hamilton cycle in G - if you do, you can prove the existence of a solution.
EDIT1:
The algorithm:
Construct directed graph G as mentioned above.
Calculate Hamilton cycle - {v1,v2,..,vn-1,v1}.
Press every number in v1.
X <- v1.
while the safe isn't open:
5.1 X <- next vertex in the Hamilton path after X.
5.2 press the last digit in X.
We can see that because we use Hamilton cycle, we never repeat the same substring. (The last 4 presses).
EDIT2:
Of course Hamilton path is sufficient.
Here in summary is the problem I think you are trying to solve and some explanation on how i might approach solving it. http://www.cs.swan.ac.uk/~csharold/cpp/SPAEcpp.pdf
You have to do some finessing to make it fit into the chinese post man problem however...
Imagine solving this problem for the binary digits, three digits strings. Assume you have the first two digits, and ask your self what are my options to move to? (In regards to the next two digit string?)
You are left with a Directed Graph.
/-\
/ V
\- 00 ----> 01
^ / ^|
\/ ||
/\ ||
V \ |V
/-- 11 ---> 10
\ ^
\-/
Solve the Chinese Postman, you will have all combinations and will form one string
The question is now, is the Chinese postman solvable? There are algorithms which determine weather or not a DAG is solvable for the CPP, but i don't know if this particular graph is necessarily solvable based on the problem alone. That would be a good thing to determine. You do however know you could find out algorithmically weather it is solvable and if it is you could solve it using algorithms available in that paper (I think) and online.
Every vertex here has 2 incoming edges and 2 outgoing edges.
There are 4 (2^2) vertexes.
In the full sized problem there are 19683( 3 ^ 9 ) vertexs and every vertex has 512 ( 2 ^ 9 ) out going and incoming vertexes. There would be a total of
19683( 3 ^ 9 ) x 512 (2 ^ 9) = 10077696 edges in your graph.
Approach to solution:
1.) Create list of all 3 digit numbers 000 to 999.
2.) Create edges for all numbers such that last two digits of first number match first
two digits of next number.
ie 123 -> 238 (valid edge) 123 -> 128 (invalid edge)
3.) use Chinese Postman solving algorithmic approaches to discover if solvable and
solve
I would create an array of subsequences which needs to be updates upon any insertion of a new digit. So in your example, it will start as:
array = {1}
then
array = {1,2,12}
then
array = {1,2,12,3,13,23,123}
then
array = {1,2,12,3,13,23,123,4,14,24,124,34,134,234,1234}
and when you have a sequence that is already at the length=4 you don't need to continue the concatenation, just remove the 1st digit of the sequence and insert the new digit at the end, for example, use the last item 1234, when we add 5 it will become 2345 as follows:
array = {1,2,12,3,13,23,123,4,14,24,124,34,134,234,1234,5,15,25,125,35,135,235,1235,45,145,245,1245,345,1345,2345,2345}
I believe that this is not a very complicated way of going over all the sub-sequences of a given sequence.

Constructing Strings using Regular Expressions and Boolean logic ||

How do I construct strings with exactly one occurrence of 111 from a set E* consisting of all possible combinations of elements in the set {0,1}?
You can generate the set of strings based on following steps:
Some chucks of numbers and their legal position are enumerated:
Start: 110
Must have one, anywhere: 111
Anywhere: 0, 010, 0110
End: 011
Depend on the length of target string (the length should be bigger than 3)
Condition 1: Length = 3 : {111}
Condition 2: 6 > Length > 3 : (Length-3) = 1x + 3y + 4z
For example, if length is 5: answer is (2,1,0) and (1,0,1)
(2,1,0) -> two '0' and one '010' -> ^0^010^ or ^010^0^ (111 can be placed in any one place marked as ^)
(1,0,1) -> one '0' and one '0110' ...
Condition 3: If 9 > Length > 6, you should consider the solution of two formulas:
Comments:
length – 3 : the length exclude 111
x: the times 0 occurred
y: the times 010 occurred
z: the times 0110 occurred
Finding all solutions {(x,y,z) | 1x + 3y + 4z = (Length - 3)} ----(1)
For each solution, you can generate one or more qualified string. For example, if you want to generate strings of length 10. One solution of (x,y,z) is (0,2,1), that means '010' should occurred twice and '0110' should occurred once. Based on this solution, the following strings can be generated:
0: x0 times
010: x 2 times
0110: x1 times
111: x1 times (must have)
Finding the permutations of elements above.
010-0110-010-111 or 111-010-010-0110 …
(Length - 6) = 1x + 3y + 4z ---(2)
Similar as above case, find all permutations to form an intermediate string.
Finally, for each intermediate string Istr, Istr + 011 or 110 + Istr are both qualified.
For example, (10-6) = 1*0 + 3*0 + 4*1 or = 1*1 + 3*1 + 4*0
The intermediate string can be composed by one '0110' for answer(0,0,1):
Then ^0110^011 and 110^0110^ are qualified strings (111 can be placed in any one place marked as ^)
Or the intermediate string can also be composed by one '0' and one '010' for answer (1,1,0)
The intermediate string can be 0 010 or 010 0
Then ^0010^011 and 110^0100^ are qualified strings (111 can be placed in any one place marked as ^)
Condition 4: If Length > 9, an addition formula should be consider:
(Length – 9) = 1x + 3y + 4z
Similar as above case, find all permutations to form an intermediate string.
Finally, for each intermediate string Istr, 110 + Istr + 011 is qualified.
Explaination:
The logic I use is based on Combinatorial Mathematics. A target string is viewed as a combination of one or more substrings. To fulfill the constraint ('111' appears exactly one time in target string), we should set criteria on substrings. '111' is definitely one substring, and it can only be used one time. Other substrings should prevent to violate the '111'-one-time constraint and also general enough to generate all possible target string.
Except the only-one-111, other substrings should not have more than two adjacent '1'. (Because if other substring have more than two adjacent 1, such as '111', '1111', '11111,' the substring will contain unnecessary '111'). Except the only-one-111, other substrings should not have more than two consecutive '1'. Because if other substring have more than two consecutive 1, such as '111', '1111', '11111,' the substring will contain unnecessary '111' . However, substrings '1' and '11' cannot ensure the only-one-111 constraint. For example, '1'+'11,' '11'+'11' or '1'+'1'+'1' all contain unnecessary '111'. To prevent unnecessary '111,' we should add '0' to stop more adjacent '1'. That results in three qualified substring '0', '010' and '0110'. Any combined string made from three qualified substring will contain zero times of '111'.
Above three qualified substring can be placeed anywhere in the target string, since they 100% ensure no additional '111' in target string.
If the substring's position is in the start or end, they can use only one '0' to prevent '111'.
In start:
10xxxxxxxxxxxxxxxxxxxxxxxxxxxx
110xxxxxxxxxxxxxxxxxxxxxxxxxxx
In end:
xxxxxxxxxxxxxxxxxxxxxxxxxxx011
xxxxxxxxxxxxxxxxxxxxxxxxxxxx01
These two cases can also ensure no additional '111'.
Based on logics mentioned above. We can generate any length of target string with exactly one '111'.
Your question could be clearer.
For one thing, does "1111" contain one occurrence of "111" or two?
If so, you want all strings that contain "111" but do not contain either "1111" or "111.*111". If not, omit the test for "1111".
If I understand you correctly, you're trying to construct an infinite subset of the infinite set of sequences of 0s and 1s. How you do that is probably going to depend on the language you're using (most languages don't have a way of representing infinite sets).
My best guess is that you want to generate a sequence of all sequences of 0s and 1s (which shouldn't be too hard) and select the ones that meet your criteria.