Scheduling Algorithm with limitations - algorithm

Thanks to user3125280, D.W. and Evgeny Kluev the question is updated.
I have a list of webpages and I must download them frequently, each webpage got a different download frequency. Based on this frequency we group the webpages in 5 groups:
Items in group 1 are downloaded once per 1 hour
items in group 2 once per 2 hours
items in group 3 once per 4 hours
items in group 4 once per 12 hours
items in group 5 once per 24 hours
This means, we must download all the group 1 webpages in 1 hour, all the group 2 in 2 hours etc.
I am trying to make an algorithm. As input, I have:
a) DATA_ARR = one array with 5 numbers. Each number represents the number of items in this group.
b) TIME_ARR = one array with 5 numbers (1, 2, 4, 12, 24) representing how often the items will be downloaded.
b) X = the total number of webpages to download per hour. This is calculated using items_in_group/download_frequently and rounded upwards. If we have 15 items in group 5, and 3 items in group 4, this will be 15/24 + 3/12 = 0.875 and rounded is 1.
Every hour my program must download at max X sites. I expect the algorithm to output something like:
Hour 1: A1 B0 C4 D5
Hour 2: A2 B1 C2 D2
...
A1 = 2nd item of 1st group
C0 = 1st item of 3rd group
My algorithm must be as efficient as possible. This means:
a) the pattern must be extendable to at least 200+ hours
b) no need to create a repeatable pattern
c) spaces are needed when possible in order to use the absolute minimum bandwidth
d) never ever download an item more often than the update frequency, no exceptions
Example:
group 1: 0 items | once per 1 hour
group 2: 3 items | once per 2 hours
group 3: 4 items | once per 4 hours
group 4: 0 items | once per 12 hours
group 5: 0 items | once per 24 hours
We calculate the number of items we can take per hour: 3/2+4/4 = 2.5. We round this upwards and it's 3.
Using pencil and paper, we can found the following solution:
Hour 1: B0 C0 B1
Hour 2: B2 C1 c2
Hour 3: B0 C3 B1
Hour 4: B2
Hour 5: B0 C0 B1
Hour 6: B2 C1 c2
Hour 7: B0 C3 B1
Hour 8: B2
Hour 9: B0 C0 B1
Hour 10: B2 C1 c2
Hour 11: B0 C3 B1
Hour 12: B2
Hour 13: B0 C0 B1
Hour 14: B2 C1 c2
and continue the above.
We take C0, C1 C2, and C3 once every 4 hours. We also take B0, B1 and B2 once every 2 hours.
Question: Please, explain to me, how to design an algorithm able to download the items, while using the absolute minimum number of downloads? Brute force is NOT a solution and the algorithm must be efficient CPU wise because the number of elements can be huge.
You may read the answer posted here: https://cs.stackexchange.com/a/19422/12497 as well as the answer posted bellow by user3125280.

You problem is a typical scheduling problem. These kinds of problems are well studied in computer science so there is a huge array of literature to consult.
The code is kind of like Deficit round robin, but with a few simplifications. First, we feed the queues ourself by adding to the data_to_process variable. Secondly, the queues just iterate through a list of values.
One difference is that this solution will get the optimal value you want, barring mathematical error.
Rough sketch: have not compiled (c++11) unix based, to spec code
#include <iostream>
#include <vector>
#include <numeric>
#include <unistd.h>
//#include <cmath> //for ceil
#define TIME_SCALE ((double)60.0) //1 for realtime speed
//Assuming you are not refreshing ints in the real case
template<typename T>
struct queue
{
const std::vector<T> data; //this will be filled with numbers
int position;
double refresh_rate; //must be refreshed ever ~ hours
double data_rate; //this many refreshes per hour
double credit; //amount of refreshes owed
queue(std::initializer_list<T> v, int r ) :
data(v), position(0), refresh_rate(r), credit(0) {
data_rate = data.size() / (double) refresh_rate;
}
int getNext() {
return data[position++ % data.size()];
}
};
double time_passed(){
static double total;
//if(total < 20){ //stop early
usleep(60000000 / TIME_SCALE); //sleep for a minute
total += 1.0 / 60.0; //add a minute
std::cout << "Time: " << total << std::endl;
return 1.0; //change to 1.0 / 60.0 for real time speed
//} else return 0;
}
int main()
{
//keep a list of the queues
std::vector<queue<int> > queues{
{{1, 2, 3}, 2},
{{1, 2, 3, 4}, 3}};
double total_data_rate = 0;
for(auto q : queues) total_data_rate += q.data_rate;
double data_to_process = 0; //how many refreshes we have to do
int queue_number = 0; //which queue we are processing
auto current_queue = &queues[0];
while(1) {
data_to_process += time_passed() * total_data_rate;
//data_to_process = ceil(data_to_process) //optional
while(data_to_process >= 1){
//data_to_process >= 0 will make the the scheduler more
//eager in the first time period (ie. everything will updated correctly
//in the first period and and following periods
if(current_queue->credit >= 1){
//don't change here though, since credit determines the weighting only,
//not how many refreshes are made
//refresh(current_queue.getNext();
std::cout << "From queue " << queue_number << " refreshed " <<
current_queue->getNext() << std::endl;
current_queue->credit -= 1;
data_to_process -= 1;
} else {
queue_number = (queue_number + 1) % queues.size();
current_queue = &queues[queue_number];
current_queue->credit += current_queue->data_rate;
}
}
}
return 0;
}
The example should now compile on gcc with --std=c++11 and give you what you want.
and here is test case output: (for non-time scaled earlier code)
Time: 0
From queue 1 refreshed 1
From queue 0 refreshed 1
From queue 1 refreshed 2
Time: 1
From queue 0 refreshed 2
From queue 0 refreshed 3
From queue 1 refreshed 3
Time: 2
From queue 0 refreshed 1
From queue 1 refreshed 4
From queue 1 refreshed 1
Time: 3
From queue 0 refreshed 2
From queue 0 refreshed 3
From queue 1 refreshed 2
Time: 4
From queue 0 refreshed 1
From queue 1 refreshed 3
From queue 0 refreshed 2
Time: 5
From queue 0 refreshed 3
From queue 1 refreshed 4
From queue 1 refreshed 1
As an extension, to answer the repeating pattern problem by allowing this scheduler to complete only the first lcm(update_rate * lcm(...refresh rates...), ceil(update_rate)) steps, and then repeating the pattern.
ALSO: this will, indeed, be unsolvable sometimes because of the requirement on hour boundaries. When I use your unsolvable example, and modify time_passed to return 0.1, the schedule is solved with updates every 1.1 hours (just not at the hour boundaries!).

It seems your constraints are all over the place. To quickly summarise my other answer:
It meets the refresh rates only on average
It does the least number of downloads at hour intervals required to fulfil the above
It was based on these (sometimes unfulfillable) constraints
Update at discrete, 1 hour intervals
Update the fewest items each time
Update each item at fixed intervals
and broke 3.
Since both the hourly interval and least-each-time constraints are not really necessary, I will give a simpler, better answer here, which breaks 2.
#include <iostream>
#include <vector>
#include <numeric>
#include <unistd.h>
#define TIME_SCALE ((double)60.0)
//Assuming you are not refreshing ints in the real case
template<typename T>
struct queue
{
const std::vector<T> data; //this is the data to refresh
int position; //this is the data we are up to
double refresh_rate; //must be refreshed every this many hours
double data_rate; //this many refreshes per hour
double credit; //is owed this many refreshes
const char* name;//a name for each queue
queue(std::initializer_list<T> v, int r, const char* n ) :
data(v), position(0), refresh_rate(r), credit(0), name(n) {
data_rate = data.size() / (double) refresh_rate;
}
void refresh() {
std::cout << "From queue " << name << " refreshed " << data[position++ % data.size()] << "\n";
}
};
double time_passed(){
static double total;
usleep(60000000 / TIME_SCALE); //sleep for a minute
total += 1.0; //add a minute
std::cout << "Time: " << total << std::endl;
return 1.0; //change to 1.0 / 60.0 for real time speed
}
int main()
{
//keep a list of the queues
std::vector<queue<int> > queues{
{{1}, 1, "A"},
{{1}, 2, "B"}};
while(1) {
auto t = time_passed();
for(queue<int>& q : queues) {
q.credit += q.data_rate * t;
while(q.credit >= 1){
q.refresh();
q.credit -= 1.0;
}
}
}
return 0;
}
It has the potential, however, to schedule many refreshes on the same hour. There is a third option as well, which breaks the hour-interval rule and updates only one at a time.
I think this is the easiest and requires the minimal number of updates (like the previous answer) but doesn't break rule 3.

Related

Algorithm to give a value to a 5 card Poker hand

I am developing a poker game as college project and our current assignment is to write an algorithm to score a hand of 5 cards, so that the scores of two hands can be compared to each other to determine which is the better hand. The score of a hand has nothing to do with the probability of what hands could be made upon the draw being dealt with random cards, etc. - The score of a hand is based solely on the 5 cards in the hand, and no other cards in the deck.
The example solution we were given was to give a default score for each type of Poker hand, with the score reflecting how good the hand is - like this for instance:
//HAND TYPES:
ROYAL_FLUSH = 900000
STRAIGHT_FLUSH = 800000
...
TWO_PAIR = 200000
ONE_PAR = 100000
Then if two hands of the same type are compared, the values of the cards in the hands should be factored into the hand's score.
So for example, the following formula could be used to score a hand:
HAND_TYPE + (each card value in the hand)^(the number of occurences of that value)
So, for a Full House of three Queens and two 7s, the score would be:
600000 + 12^3 + 7^2
This formula works for the most part, but I have determined that in some instances, two similar hands can return the exact same score, when one should actually beat the other. An example of this is:
hand1 = 4C, 6C, 6H, JS, KC
hand2 = 3H, 4H, 7C, 7D, 8H
These two hands both have one pair, so their respective scores are:
100000 + 4^1 + 6^2 + 11^1 + 13^1 = 100064
100000 + 3^1 + 4^1 + 7^2 + 8^1 = 100064
This results in a draw, when clearly a pair of 7s trumps a pair of 6s.
How can I improve this formula, or even, what is a better formula I can use?
By the way, in my code, hands are stored in an array of each card's value in ascending order, for example:
[2H, 6D, 10C, KS, AS]
EDIT:
Here is my final solution thanks to the answers below:
/**
* Sorts cards by putting the "most important" cards first, and the rest in decreasing order.
* e.g. High Hand: KS, 9S, 8C, 4D, 2H
* One Pair: 3S, 3D, AH, 7S, 2C
* Full House: 6D, 6C, 6S, JC, JH
* Flush: KH, 9H, 7H, 6H, 3H
*/
private void sort() {
Arrays.sort(hand, Collections.reverseOrder()); // Initially sorts cards in descending order of game value
if (isFourOfAKind()) { // Then adjusts for hands where the "most important" cards
sortFourOfAKind(); // must come first
} else if (isFullHouse()) {
sortFullHouse();
} else if (isThreeOfAKind()) {
sortThreeOfAKind();
} else if (isTwoPair()) {
sortTwoPair();
} else if (isOnePair()){
sortOnePair();
}
}
private void sortFourOfAKind() {
if (hand[0].getGameValue() != hand[HAND_SIZE - 4].getGameValue()) { // If the four of a kind are the last four cards
swapCardsByIndex(0, HAND_SIZE - 1); // swap the first and last cards
} // e.g. AS, 9D, 9H, 9S, 9C => 9C, 9D, 9H, 9S, AS
}
private void sortFullHouse() {
if (hand[0].getGameValue() != hand[HAND_SIZE - 3].getGameValue()) { // If the 3 of a kind cards are the last three
swapCardsByIndex(0, HAND_SIZE - 2); // swap cards 1 and 4, 2 and 5
swapCardsByIndex(HAND_SIZE - 4, HAND_SIZE - 1); // e.g. 10D, 10C, 6H, 6S, 6D => 6S, 6D, 6H, 10D, 10C
}
}
private void sortThreeOfAKind() { // If the 3 of a kind cards are the middle 3 cards
if (hand[0].getGameValue() != hand[HAND_SIZE - 3].getGameValue() && hand[HAND_SIZE - 1].getGameValue() != hand[HAND_SIZE - 3].getGameValue()) { // swap cards 1 and 4
swapCardsByIndex(0, HAND_SIZE - 2); // e.g. AH, 8D, 8S, 8C, 7D => 8C, 8D, 8S, AH, 7D
} else if (hand[0].getGameValue() != hand[HAND_SIZE - 3].getGameValue() && hand[HAND_SIZE - 4].getGameValue() != hand[HAND_SIZE - 3].getGameValue()) {
Arrays.sort(hand); // If the 3 of a kind cards are the last 3,
swapCardsByIndex(HAND_SIZE - 1, HAND_SIZE - 2); // reverse the order (smallest game value to largest)
} // then swap the last two cards (maintain the large to small ordering)
} // e.g. KS, 9D, 3C, 3S, 3H => 3H, 3S, 3C, 9D, KS => 3H, 3S, 3C, KS, 9D
private void sortTwoPair() {
if (hand[0].getGameValue() != hand[HAND_SIZE - 4].getGameValue()) { // If the two pairs are the last 4 cards
for (int i = 0; i < HAND_SIZE - 1; i++) { // "bubble" the first card to the end
swapCardsByIndex(i, i + 1); // e.g. AH, 7D, 7S, 6H, 6C => 7D, 7S, 6H, 6C, AH
}
} else if (hand[0].getGameValue() == hand[HAND_SIZE - 4].getGameValue() && hand[HAND_SIZE - 2].getGameValue() == hand[HAND_SIZE - 1].getGameValue()) { // If the two pairs are the first and last two cards
swapCardsByIndex(HAND_SIZE - 3, HAND_SIZE - 1); // swap the middle and last card
} // e.g. JS, JC, 8D, 4H, 4S => JS, JC, 4S, 4H, 8D
}
private void sortOnePair() { // If the pair are cards 2 and 3, swap cards 1 and 3
if (hand[HAND_SIZE - 4].getGameValue() == hand[HAND_SIZE - 3].getGameValue()) { // e.g QD, 8H, 8C, 6S, 4J => 8C, 8H, QD, 6S, 4J
swapCardsByIndex(0, HAND_SIZE - 3);
} else if (hand[HAND_SIZE - 3].getGameValue() == hand[HAND_SIZE - 2].getGameValue()) { // If the pair are cards 3 and 4, swap 1 and 3, 2 and 4
swapCardsByIndex(0, HAND_SIZE - 3); // e.g. 10S, 8D, 4C, 4H, 2H => 4C, 4H, 10S, 8D, 2H
swapCardsByIndex(HAND_SIZE - 4, HAND_SIZE - 2);
} else if (hand[HAND_SIZE - 2].getGameValue() == hand[HAND_SIZE - 1].getGameValue()) { // If the pair are the last 2 cards, reverse the order
Arrays.sort(hand); // and then swap cards 3 and 5
swapCardsByIndex(HAND_SIZE - 3, HAND_SIZE - 1); // e.g. 9H, 7D, 6C, 3D, 3S => 3S, 3D, 6C, 7D, 9H => 3S, 3D, 9H, 7D, 6C
}
}
/**
* Swaps the two cards of the hand at the indexes taken as parameters
* #param index1
* #param index2
*/
private void swapCardsByIndex(int index1, int index2) {
PlayingCard temp = hand[index1];
hand[index1] = hand[index2];
hand[index2] = temp;
}
/**
* Gives a unique value of any hand, based firstly on the type of hand, and then on the cards it contains
* #return The Game Value of this hand
*
* Firstly, a 24 bit binary string is created where the most significant 4 bits represent the value of the type of hand
* (defined as constants private to this class), the last 20 bits represent the values of the 5 cards in the hand, where
* the "most important" cards are at greater significant places. Finally, the binary string is converter to an integer.
*/
public int getGameValue() {
String handValue = addPaddingToBinaryString(Integer.toBinaryString(getHandValue()));
for (int i = 0; i < HAND_SIZE; i++) {
handValue += addPaddingToBinaryString(Integer.toBinaryString(getCardValue(hand[i])));
}
return Integer.parseInt(handValue, 2);
}
/**
* #param binary
* #return the same binary string padded to 4 bits long
*/
private String addPaddingToBinaryString(String binary) {
switch (binary.length()) {
case 1: return "000" + binary;
case 2: return "00" + binary;
case 3: return "0" + binary;
default: return binary;
}
}
/**
* #return Default value for the type of hand
*/
private int getHandValue() {
if (isRoyalFlush()) { return ROYAL_FLUSH_VALUE; }
if (isStraightFlush()) { return STRAIGHT_FLUSH_VALUE; }
if (isFourOfAKind()) { return FOUR_OF_A_KIND_VALUE; }
if (isFullHouse()) { return FULL_HOUSE_VALUE; }
if (isFlush()) { return FLUSH_VALUE; }
if (isStraight()) { return STRAIGHT_VALUE; }
if (isThreeOfAKind()) { return THREE_OF_A_KIND_VALUE; }
if (isTwoPair()) { return TWO_PAIR_VALUE; }
if (isOnePair()) { return ONE_PAIR_VALUE; }
return 0;
}
/**
* #param card
* #return the value for a given card type, used to calculate the Hand's Game Value
* 2H = 0, 3D = 1, 4S = 2, ... , KC = 11, AH = 12
*/
private int getCardValue(PlayingCard card) {
return card.getGameValue() - 2;
}
There are 10 recognized poker hands:
9 - Royal flush
8 - Straight flush (special case of royal flush, really)
7 - Four of a kind
6 - Full house
5 - Flush
4 - Straight
3 - Three of a kind
2 - Two pair
1 - Pair
0 - High card
If you don't count suit, there are only 13 possible card values. The card values are:
2 - 0
3 - 1
4 - 2
5 - 3
6 - 4
7 - 5
8 - 6
9 - 7
10 - 8
J - 9
Q - 10
K - 11
A - 12
It takes 4 bits to code the hand, and 4 bits each to code the cards. You can code an entire hand in 24 bits.
A royal flush would be 1001 1100 1011 1010 1001 1000 (0x9CBA98)
A 7-high straight would be 0100 0101 0100 0011 0010 0001 (0x454321)
Two pair, 10s and 5s (and an ace) would be 0010 1000 1000 0011 0011 1100 (0x28833C)
I assume you have logic that will figure out what hand you have. In that, you've probably written code to arrange the cards in left-to-right order. So a royal flush would be arranged as [A,K,Q,J,10]. You can then construct the number that represents the hand using the following logic:
int handValue = HandType; (i.e. 0 for high card, 7 for Four of a kind, etc.)
for each card
handValue = (handValue << 4) + cardValue (i.e. 0 for 2, 9 for Jack, etc.)
The result will be a unique value for each hand, and you're sure that a Flush will always beat a Straight and a king-high Full House will beat a 7-high Full House, etc.
Normalizing the hand
The above algorithm depends on the poker hand being normalized, with the most important cards first. So, for example, the hand [K,A,10,J,Q] (all of the same suit) is a royal flush. It's normalized to [A,K,Q,J,10]. If you're given the hand [10,Q,K,A,J], it also would be normalized to [A,K,Q,J,10]. The hand [7,4,3,2,4] is a pair of 4's. It will be normalized to [4,4,7,3,2].
Without normalization, it's very difficult to create a unique integer value for every hand and guarantee that a pair of 4's will always beat a pair of 3's.
Fortunately, sorting the hand is part of figuring out what the hand is. You could do that without sorting, but sorting five items takes a trivial amount of time and it makes lots of things much easier. Not only does it make determining straights easier, it groups common cards together, which makes finding pairs, triples, and quadruples easier.
For straights, flushes, and high card hands, all you need to do is sort. For the others, you have to do a second ordering pass that orders by grouping. For example a full house would be xxxyy, a pair would be xxabc, (with a, b, and c in order), etc. That work is mostly done for you anyway, by the sort. All you have to do is move the stragglers to the end.
As you have found, if you add together the values of the cards in the way you have proposed then you can get ambiguities.
100000 + 4^1 + 6^2 + 11^1 + 13^1 = 100064
100000 + 3^1 + 4^1 + 7^2 + 8^1 = 100064
However, addition is not quite the right tool here. You are already using ^ which means you're partway there. Use multiplication instead and you can avoid ambiguities. Consider:
100000 + (4^1 * 6^2 * 11^1 * 13^1)
100000 + (3^1 * 4^1 * 7^2 * 8^1)
This is nearly correct, but there are still ambiguities (for example 2^4 = 4^2). So, reassign new (prime!) values to each card:
Ace => 2
3 => 3
4 => 5
5 => 7
6 => 11
...
Then, you can multiply the special prime values of each card together to produce a unique value for every possible hand. Add in your value for type of hand (pair, full house, flush, etc) and use that. You may need to increase the magnitude of your hand type values so they stay out of the way of the card value composite.
The highest value for a card will be 14, assuming you let non-face cards keep their value (2..10), then J=11, QK, A=14.
The purpose of the scoring would be to differentiate between hands in a tie-breaking scenario. That is, "pair" vs. "pair." If you detect a different hand configuration ("two pair"), that puts the scores into separate groups.
You should carefully consult your requirements. I suspect that at least for some hands, the participating cards are more important than non-participating cards. For example, does a pair of 4's with a 7-high beat a pair of 3's with a queen-high? (Is 4,4,7,3,2 > 3,3,Q,6,5?) The answer to this should determine an ordering for the cards in the hand.
Given you have 5 cards, and the values are < 16, convert each card to a hexadecimal digit: 2..10,JQKA => 2..ABCDE. Put the cards in order, as determined above. For example, 4,4,7,3,2 will probably become 4,4,7,3,2. Map those values to hex, and then to an integer value: "0x44732" -> 0x44732.
Let your combo scores be multiples of 0x100000, to ensure that no card configuration can promote a hand into a higher class, then add them up.

Cyclomatic Complexity number - do I have to count every statement separately as node?

I came across different ways of calculating CCN (according to formula CCN = E-N+2P)
One way was to count all the lines in the code separately and the other way is to count a few lines of code as one step; lets have the following example:
1 public class SumAndAverage {
2
3 public static void main (String[] args) {
4 int sum = 0;
5 double average = 0.0;
6 String message = "";
7
8 int num = Integer.parseInt(args[0]);
9
10 if ((num < 1) || (num > 100)) {
11 message = "Invalid number entered.";
12 } else {
13 for (int i = 1; i <= num; i++) {
14 sum += i;
15 }
16 average = (double) sum / num;
17 message = "The sum is " + sum + " and the average is " + average;
18 }
19 System.out.println(message);
20 }
21}
Counting every statement we'd get 12 - 11 + 2x 1 = 3
I was wondering if I "join" lines 4,5,6,8 and count them as one step and do the same with line 16 and 17, would that be correct too? The result would be the same as no of edges would also decrease: 8 - 7 + 2*1 = 3
The right way to calculate complexity is by considering blocks of code. A block of code is where there is no chance of dissecting the execution path.
McCabe's paper mentions the below:
The tool, FLOW, was written in APL to input the source code from Fortran files on disk. FLOW would then break a Fortran job into distinct subroutines and analyze the control structure of each subroutine. It does this by breaking the Fortran subroutines into blocks that are delimited by statements that affect control flow: IF, GOTO ,referenced LABELS, DO, etc.
For other information on complexity, also read through Cyclomatic complexity as a Quality measure

Generating number within range with equal probability with dice

I've been thinking about this but can't seem to figure it out. I need to pick a random integer between 1 to 50 (inclusive) in such a way that each of the integer in it would be equally likely. I will have to do this using a 8 sided dice and a 15 sided dice.
I've read somewhat similar questions related to random number generators with dices but I am still confused. I think it is somewhere along the line of partitioning the numbers into sets. Then, I would roll a die, and then, depending on the outcome, decide which die to roll again.
Can someone help me with this?
As a simple - not necessarily "optimal" solution, roll the 8 sided die, then the 15 sided:
8 sided 15 sided 1..50 result
1 or 2 1..15 1..15
3 or 4 1..15 16..30 (add 15 to 15-sided roll)
5 or 6 1..15 31..45 (add 30 to 15-sided roll)
7 or 8 1..5 46..50 (add 45 to 15-sided roll)
7 or 8 6..15 start again / reroll both dice
lets say you have two functions: d8(), which returns a number from 0 to 7, and d15(), which returns a number from 0 to 14. You want to write a d50() that returns a number from 0 to 49.
Of all the simple ways, this one is probably the most efficient in terms of how many dice you have to roll, and something like this will work for all combinations of dice you have and dice you want:
int d50()
{
int result;
do
{
result = d8()*8+d8(); //random from 0 to 63
} while(result >=50);
return result;
}
If you want really constant time, you can do this:
int d50()
{
int result = d15();
int result = result*15+d15(); //0 to 225
int result = result*8+d8(); //0 to 1799
return result/36; //integer division rounds down
}
This way combines dice until the number of possibilities (1800) is evenly divisible by 50, so the same number of possibilities correspond to each result. This works OK in this case, but doesn't work if the prime factors of the dice you have (2, 3, and 5 in this case), don't cover the factors of the dice you want (2, 5)
I think that you can consider each dice result as a subdivision of a bigger interval. So throwing one 8 sided dice you choose one out the 8 major interval that divide your range of value. Throwing a 15 sided dice means selecting one out the 15 sub-interval and so on.
Considering that 15 = 3*5, 8 = 2*2*2 and 50 = 2*5*5 you can choose 36 = 3*3*2*2 as an handy multiple of 50 so that:
15*15*8 = 50*36 = 1800
You can even think of expressing the numbers from 0 to 1799 in base 15 and choose ramdomly the three digits:
choice = [0-7]*15^2 + [0-14]*15^1 + [0-14]*15^0
So my proposal, with a test of the distribution, is (in the c++ language):
#include <iostream>
#include <random>
#include <map>
int main() {
std::map<int, int> hist;
int result;
std::random_device rd;
std::mt19937 gen(rd()); // initialiaze the random generator
std::uniform_int_distribution<> d8(0, 7); // istantiate the dices
std::uniform_int_distribution<> d15(0, 14);
for (int i = 0; i < 20000; ++i) { // make a lot of throws...
result = d8(gen) * 225;
result += d15(gen) * 15; // add to result
result += d15(gen);
++hist[ result / 36 + 1]; // count each result
}
for (auto p : hist) { // show the occurences of each result
std::cout << p.first << " : " << p.second << '\n';
}
return 0;
}
The output should be something like this:
1 : 387
2 : 360
3 : 377
4 : 393
5 : 402
...
48 : 379
49 : 378
50 : 420

Distinct number of changes in real time data

Hi I am taking in data in real time where the value goes from 1009 , 1008 o 1007 to 0. I am trying to count the number of distinct times this occurs, for example the snippet below should count 2 distinct periods of change.
1008
1009
1008
0
0
0
1008
1007
1008
1008
1009
9
0
0
1009
1008
I have written a for loop as below but I can't figure out if the logic is correct as I get multiple increments instead of just the one
if(current != previous && current < 100)
x++;
else
x = x;
You tagged this with the LabVIEW tag. Is this actually supposed to be LabVIEW code?
Your logic has a bug related to the noise you say you have - if the value is less than 100 and it changes (for instance from 9 to 0), you log that as a change. You also have a line which doesn't do anything (x=x), although if this is supposed to be LV code, then this could make sense.
The code you posted here does not seem to make sense to me if I understand your goal. My understanding is that you want to identify this specific pattern:
1009
1008
1007
0
And that any deviation from this sequence of numbers would constitute data that should be ignored. To this end, you should be monitoring the history of the past 3 numbers. In C you might write this logic in the following way:
#include <stdio.h>
//Function to get the next value from our data stream.
int getNext(int *value) {
//Variable to hold our return code.
int code;
//Replace following line to get gext number from the stream. Possible read from a file?
*value = 0;
//Replace following logic to set 'code' appropriately.
if(*value == -1)
code = -1;
else
code = 0;
//Return 'code' to the caller.
return code;
}
//Example application for counting the occurrences of the sequence '1009','1008','1007','0'.
int main(int argc, char **argv) {
//Declare 4 items to store the past 4 items in the sequence (x0-x3)
//Declare a count and a flag to monitor the occurrence of our pattern
int x0 = 0, x1 = 0, x2 = 0, x3 = 0, count = 0, occurred = 0;
//Run forever (just as an example, you would provide your own looping structure or embed the algorithm in your app).
while(1) {
//Get the next element (implement getNext to provide numbers from your data source).
//If the function returns non-zero, exit the loop and print the count.
if( getNext(&x0) != 0 )
break;
//If the newest element is 0, we can trigger a check of the prior 3.
if(x0 == 0) {
//Set occurred to 0 if the prior elements don't match our pattern.
occurred = (x1 == 1007) && (x2 == 1008) && (x3 == 1009);
if(occurred) {
//Occurred was 1, meaning the pattern was matched. Increment our count.
count++;
//Reset occurred
occurred = 0;
}
//If the newest element is not 0, dont bother checking. Just shift the elements down our list.
} else {
x3 = x2; //Shift 3rd element to 4th position
x2 = x1; //Shift 2nd element to 3rd position
x1 = x0; //Shift 1st element to 2nd position
}
}
printf("The pattern count is %d\n", count);
//Exit application
return 0;
}
Note that the getNext function is just shown here as an example but obviously what I have implemented will not work. This function should be implemented based on how you are extracting data from the stream.
Writing the application in this way might not make sense within your larger application but the algorithm is what you should take away from this. Essentially you want to buffer 4 elements in a rolling window. You push the newest element into x0 and shift the others down. After this process you check the four elements to see if they match your desired pattern and increment the count accordingly.
If the requirement is to count falling edges and you don't care about the specific level, and want to reject noise band or ripple in the steady state then just make the conditional something like
if ((previous - current) > threshold)
No complex shifting, history, or filtering required. Depending on the application you can follow up with a debounce (persistency check) to ignore spurious samples (just keep track of falling/rising, or fell/rose as simple toggling state spanning a desired number of samples).
Code to the pattern, not the specific values; use constant or adjustable parameters to control the value sensitivity.

What is the fastest possible way to sort an array of 7 integers?

This is a part of a program that analyzes the odds of poker, specifically Texas Hold'em. I have a program I'm happy with, but it needs some small optimizations to be perfect.
I use this type (among others, of course):
type
T7Cards = array[0..6] of integer;
There are two things about this array that may be important when deciding how to sort it:
Every item is a value from 0 to 51. No other values are possible.
There are no duplicates. Never.
With this information, what is the absolutely fastest way to sort this array? I use Delphi, so pascal code would be the best, but I can read C and pseudo, albeit a bit more slowly :-)
At the moment I use quicksort, but the funny thing is that this is almost no faster than bubblesort! Possible because of the small number of items. The sorting counts for almost 50% of the total running time of the method.
EDIT:
Mason Wheeler asked why it's necessary to optimize. One reason is that the method will be called 2118760 times.
Basic poker information: All players are dealt two cards (the pocket) and then five cards are dealt to the table (the 3 first are called the flop, the next is the turn and the last is the river. Each player picks the five best cards to make up their hand)
If I have two cards in the pocket, P1 and P2, I will use the following loops to generate all possible combinations:
for C1 := 0 to 51-4 do
if (C1<>P1) and (C1<>P2) then
for C2 := C1+1 to 51-3 do
if (C2<>P1) and (C2<>P2) then
for C3 := C2+1 to 51-2 do
if (C3<>P1) and (C3<>P2) then
for C4 := C3+1 to 51-1 do
if (C4<>P1) and (C4<>P2) then
for C5 := C4+1 to 51 do
if (C5<>P1) and (C5<>P2) then
begin
//This code will be executed 2 118 760 times
inc(ComboCounter[GetComboFromCards([P1,P2,C1,C2,C3,C4,C5])]);
end;
As I write this I notice one thing more: The last five elements of the array will always be sorted, so it's just a question of putting the first two elements in the right position in the array. That should simplify matters a bit.
So, the new question is: What is the fastest possible way to sort an array of 7 integers when the last 5 elements are already sorted. I believe this could be solved with a couple (?) of if's and swaps :-)
For a very small set, insertion sort can usually beat quicksort because it has very low overhead.
WRT your edit, if you're already mostly in sort order (last 5 elements are already sorted), insertion sort is definitely the way to go. In an almost-sorted set of data, it'll beat quicksort every time, even for large sets. (Especially for large sets! This is insertion sort's best-case scenario and quicksort's worst case.)
Don't know how you are implementing this, but what you could do is have an array of 52 instead of 7, and just insert the card in its slot directly when you get it since there can never be duplicates, that way you never have to sort the array. This might be faster depending on how its used.
I don't know that much about Texas Hold'em: Does it matter what suit P1 and P2 are, or does it only matter if they are of the same suit or not? If only suit(P1)==suit(P2) matters, then you could separate the two cases, you have only 13x12/2 different possibilities for P1/P2, and you can easily precalculate a table for the two cases.
Otherwise, I would suggest something like this:
(* C1 < C2 < P1 *)
for C1:=0 to P1-2 do
for C2:=C1+1 to P1-1 do
Cards[0] = C1;
Cards[1] = C2;
Cards[2] = P1;
(* generate C3...C7 *)
(* C1 < P1 < C2 *)
for C1:=0 to P1-1 do
for C2:=P1+1 to 51 do
Cards[0] = C1;
Cards[1] = P1;
Cards[2] = C2;
(* generate C3...C7 *)
(* P1 < C1 < C2 *)
for C1:=P1+1 to 51 do
for C2:=C1+1 to 51 do
Cards[0] = P1;
Cards[1] = C1;
Cards[2] = C2;
(* generate C3...C7 *)
(this is just a demonstration for one card P1, you would have to expand that for P2, but I think that's straightforward. Although it'll be a lot of typing...)
That way, the sorting doesn't take any time at all. The generated permutations are already ordered.
There are only 5040 permutations of 7 elements. You can programmaticaly generate a program that finds the one represented by your input in a minimal number of comparisons. It will be a big tree of if-then-else instructions, each comparing a fixed pair of nodes, for example if (a[3]<=a[6]).
The tricky part is deciding which 2 elements to compare in a particular internal node. For this, you have to take into account the results of comparisons in the ancestor nodes from root to the particular node (for example a[0]<=a[1], not a[2]<=a[7], a[2]<=a[5]) and the set of possible permutations that satisfy the comparisons. Compare the pair of elements that splits the set into as equal parts as possible (minimize the size of the larger part).
Once you have the permutation, it is trivial to sort it in a minimal set of swaps.
Since the last 5 items are already sorted, the code can be written just to reposition the first 2 items. Since you're using Pascal, I've written and tested a sorting algorithm that can execute 2,118,760 times in about 62 milliseconds.
procedure SortT7Cards(var Cards: T7Cards);
const
CardsLength = Length(Cards);
var
I, J, V: Integer;
V1, V2: Integer;
begin
// Last 5 items will always be sorted, so we want to place the first two into
// the right location.
V1 := Cards[0];
V2 := Cards[1];
if V2 < V1 then
begin
I := V1;
V1 := V2;
V2 := I;
end;
J := 0;
I := 2;
while I < CardsLength do
begin
V := Cards[I];
if V1 < V then
begin
Cards[J] := V1;
Inc(J);
Break;
end;
Cards[J] := V;
Inc(J);
Inc(I);
end;
while I < CardsLength do
begin
V := Cards[I];
if V2 < V then
begin
Cards[J] := V2;
Break;
end;
Cards[J] := V;
Inc(J);
Inc(I);
end;
if J = (CardsLength - 2) then
begin
Cards[J] := V1;
Cards[J + 1] := V2;
end
else if J = (CardsLength - 1) then
begin
Cards[J] := V2;
end;
end;
Use min-sort. Search for minimal and maximal element at once and place them into resultant array. Repeat three times. (EDIT: No, I won't try to measure the speed theoretically :_))
var
cards,result: array[0..6] of integer;
i,min,max: integer;
begin
n=0;
while (n<3) do begin
min:=-1;
max:=52;
for i from 0 to 6 do begin
if cards[i]<min then min:=cards[i]
else if cards[i]>max then max:=cards[i]
end
result[n]:=min;
result[6-n]:=max;
inc(n);
end
for i from 0 to 6 do
if (cards[i]<52) and (cards[i]>=0) then begin
result[3] := cards[i];
break;
end
{ Result is sorted here! }
end
This is the fastest method: since the 5-card list is already sorted, sort the two-card list (a compare & swap), and then merge the two lists, which is O(k * (5+2). In this case (k) will normally be 5: the loop test(1), the compare(2), the copy(3), the input-list increment(4) and the output list increment(5). That's 35 + 2.5. Throw in loop initialization and you get 41.5 statements, total.
You could also unroll the loops which would save you maybe 8 statements or execution, but make the whole routine about 4-5 times longer which may mess with your instruction cache hit ratio.
Given P(0 to 2), C(0 to 5) and copying to H(0 to 6)
with C() already sorted (ascending):
If P(0) > P(1) Then
// Swap:
T = P(0)
P(0) = P(1)
P(1) = T
// 1stmt + (3stmt * 50%) = 2.5stmt
End
P(2), C(5) = 53 \\ Note these are end-of-list flags
k = 0 \\ P() index
J = 0 \\ H() index
i = 0 \\ C() index
// 4 stmt
Do While (j) < 7
If P(k) < C(I) then
H(j) = P(k)
k = k+1
Else
H(j) = C(i)
j = j+1
End if
j = j+1
// 5stmt * 7loops = 35stmt
Loop
And note that this is faster than the other algorithm that would be "fastest" if you had to truly sort all 7 cards: use a bit-mask(52) to map & bit-set all 7 cards into that range of all possible 52 cards (the bit-mask), and then scan the bit-mask in order looking for the 7 bits that are set. That takes 60-120 statements at best (but is still faster than any other sorting approach).
For seven numbers, the most efficient algorithm that exists with regards to the number of comparisons is Ford-Johnson's. In fact, wikipedia references a paper, easily found on google, that claims Ford-Johnson's the best for up to 47 numbers. Unfortunately, references to Ford-Johnson's aren't all that easy to found, and the algorithm uses some complex data structures.
It appears on The Art Of Computer Programming, Volume 3, by Donald Knuth, if you have access to that book.
There's a paper which describes FJ and a more memory efficient version here.
At any rate, because of the memory overhead of that algorithm, I doubt it would be worth your while for integers, as the cost of comparing two integers is rather cheap compared to the cost of allocating memory and manipulating pointers.
Now, you mentioned that 5 cards are already sorted, and you just need to insert two. You can do this with insertion sort most efficiently like this:
Order the two cards so that P1 > P2
Insert P1 going from the high end to the low end
(list) Insert P2 going from after P1 to the low end
(array) Insert P2 going from the low end to the high end
How you do that will depend on the data structure. With an array you'll be swapping each element, so place P1 at 1st, P2 and 7th (ordered high to low), and then swap P1 up, and then P2 down. With a list, you just need to fix the pointers as appropriate.
However once more, because of the particularity of your code, it really is best if you follow nikie suggestion and just generate the for loops apropriately for every variation in which P1 and P2 can appear in the list.
For example, sort P1 and P2 so that P1 < P2. Let's make Po1 and Po2 the position from 0 to 6, of P1 and P2 on the list. Then do this:
Loop Po1 from 0 to 5
Loop Po2 from Po1 + 1 to 6
If (Po2 == 1) C1start := P2 + 1; C1end := 51 - 4
If (Po1 == 0 && Po2 == 2) C1start := P1+1; C1end := P2 - 1
If (Po1 == 0 && Po2 > 2) C1start := P1+1; C1end := 51 - 5
If (Po1 > 0) C1start := 0; C1end := 51 - 6
for C1 := C1start to C1end
// Repeat logic to compute C2start and C2end
// C2 can begin at C1+1, P1+1 or P2+1
// C2 can finish at P1-1, P2-1, 51 - 3, 51 - 4 or 51 -5
etc
You then call a function passing Po1, Po2, P1, P2, C1, C2, C3, C4, C5, and have this function return all possible permutations based on Po1 and Po2 (that's 36 combinations).
Personally, I think that's the fastest you can get. You completely avoid having to order anything, because the data will be pre-ordered. You incur in some comparisons anyway to compute the starts and ends, but their cost is minimized as most of them will be on the outermost loops, so they won't be repeated much. And they can even be more optimized at the cost of more code duplication.
For 7 elements, there are only few options. You can easily write a generator that produces method to sort all possible combinations of 7 elements. Something like this method for 3 elements:
if a[1] < a[2] {
if a[2] < a[3] {
// nothing to do, a[1] < a[2] < a[3]
} else {
if a[1] < a[3] {
// correct order should be a[1], a[3], a[2]
swap a[2], a[3]
} else {
// correct order should be a[3], a[1], a[2]
swap a[2], a[3]
swap a[1], a[3]
}
}
} else {
// here we know that a[1] >= a[2]
...
}
Of course method for 7 elements will be bigger, but it's not that hard to generate.
The code below is close to optimal. It could be made better by composing a list to be traversed while making the tree, but I'm out of time right now. Cheers!
object Sort7 {
def left(i: Int) = i * 4
def right(i: Int) = i * 4 + 1
def up(i: Int) = i * 4 + 2
def value(i: Int) = i * 4 + 3
val a = new Array[Int](7 * 4)
def reset = {
0 until 7 foreach {
i => {
a(left(i)) = -1
a(right(i)) = -1
a(up(i)) = -1
a(value(i)) = scala.util.Random.nextInt(52)
}
}
}
def sortN(i : Int) {
var index = 0
def getNext = if (a(value(i)) < a(value(index))) left(index) else right(index)
var next = getNext
while(a(next) != -1) {
index = a(next)
next = getNext
}
a(next) = i
a(up(i)) = index
}
def sort = 1 until 7 foreach (sortN(_))
def print {
traverse(0)
def traverse(i: Int): Unit = {
if (i != -1) {
traverse(a(left(i)))
println(a(value(i)))
traverse(a(right(i)))
}
}
}
}
In pseudo code:
int64 temp = 0;
int index, bit_position;
for index := 0 to 6 do
temp |= 1 << cards[index];
for index := 0 to 6 do
begin
bit_position = find_first_set(temp);
temp &= ~(1 << bit_position);
cards[index] = bit_position;
end;
It's an application of bucket sort, which should generally be faster than any of the comparison sorts that were suggested.
Note: The second part could also be implemented by iterating over bits in linear time, but in practice it may not be faster:
index = 0;
for bit_position := 0 to 51 do
begin
if (temp & (1 << bit_position)) > 0 then
begin
cards[index] = bit_position;
index++;
end;
end;
Assuming that you need an array of cards at the end of it.
Map the original cards to bits in a 64 bit integer ( or any integer with >= 52 bits ).
If during the initial mapping the array is sorted, don't change it.
Partition the integer into nibbles - each will correspond to values 0x0 to 0xf.
Use the nibbles as indices to corresponding sorted sub-arrays. You'll need 13 sets of 16 sub-arrays ( or just 16 sub-arrays and use a second indirection, or do the bit ops rather than looking the answer up; what is faster will vary by platform ).
Concatenate the non-empty sub-arrays into the final array.
You could use larger than nibbles if you want; bytes would give 7 sets of 256 arrays and make it more likely that the non-empty arrays require concatenating.
This assumes that branches are expensive and cached array accesses cheap.
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
// for general case of 7 from 52, rather than assuming last 5 sorted
uint32_t card_masks[16][5] = {
{ 0, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0 },
{ 2, 0, 0, 0, 0 },
{ 1, 2, 0, 0, 0 },
{ 3, 0, 0, 0, 0 },
{ 1, 3, 0, 0, 0 },
{ 2, 3, 0, 0, 0 },
{ 1, 2, 3, 0, 0 },
{ 4, 0, 0, 0, 0 },
{ 1, 4, 0, 0, 0 },
{ 2, 4, 0, 0, 0 },
{ 1, 2, 4, 0, 0 },
{ 3, 4, 0, 0, 0 },
{ 1, 3, 4, 0, 0 },
{ 2, 3, 4, 0, 0 },
{ 1, 2, 3, 4, 0 },
};
void sort7 ( uint32_t* cards) {
uint64_t bitset = ( ( 1LL << cards[ 0 ] ) | ( 1LL << cards[ 1LL ] ) | ( 1LL << cards[ 2 ] ) | ( 1LL << cards[ 3 ] ) | ( 1LL << cards[ 4 ] ) | ( 1LL << cards[ 5 ] ) | ( 1LL << cards[ 6 ] ) ) >> 1;
uint32_t* p = cards;
uint32_t base = 0;
do {
uint32_t* card_mask = card_masks[ bitset & 0xf ];
// you might remove this test somehow, as well as unrolling the outer loop
// having separate arrays for each nibble would save 7 additions and the increment of base
while ( *card_mask )
*(p++) = base + *(card_mask++);
bitset >>= 4;
base += 4;
} while ( bitset );
}
void print_cards ( uint32_t* cards ) {
printf ( "[ %d %d %d %d %d %d %d ]\n", cards[0], cards[1], cards[2], cards[3], cards[4], cards[5], cards[6] );
}
int main ( void ) {
uint32_t cards[7] = { 3, 9, 23, 17, 2, 42, 52 };
print_cards ( cards );
sort7 ( cards );
print_cards ( cards );
return 0;
}
Use a sorting network, like in this C++ code:
template<class T>
inline void sort7(T data) {
#define SORT2(x,y) {if(data##x>data##y)std::swap(data##x,data##y);}
//DD = Define Data, create a local copy of the data to aid the optimizer.
#define DD1(a) register auto data##a=*(data+a);
#define DD2(a,b) register auto data##a=*(data+a);register auto data##b=*(data+b);
//CB = Copy Back
#define CB1(a) *(data+a)=data##a;
#define CB2(a,b) *(data+a)=data##a;*(data+b)=data##b;
DD2(1,2) SORT2(1,2)
DD2(3,4) SORT2(3,4)
DD2(5,6) SORT2(5,6)
DD1(0) SORT2(0,2)
SORT2(3,5)
SORT2(4,6)
SORT2(0,1)
SORT2(4,5)
SORT2(2,6) CB1(6)
SORT2(0,4)
SORT2(1,5)
SORT2(0,3) CB1(0)
SORT2(2,5) CB1(5)
SORT2(1,3) CB1(1)
SORT2(2,4) CB1(4)
SORT2(2,3) CB2(2,3)
#undef CB1
#undef CB2
#undef DD1
#undef DD2
#undef SORT2
}
Use the function above if you want to pass it an iterator or a pointer and use the function below if you want to pass it the seven arguments one by one. BTW, using templates allows compilers to generate really optimized code so don't get ride of the template<> unless you want C code (or some other language's code).
template<class T>
inline void sort7(T& e0, T& e1, T& e2, T& e3, T& e4, T& e5, T& e6) {
#define SORT2(x,y) {if(data##x>data##y)std::swap(data##x,data##y);}
#define DD1(a) register auto data##a=e##a;
#define DD2(a,b) register auto data##a=e##a;register auto data##b=e##b;
#define CB1(a) e##a=data##a;
#define CB2(a,b) e##a=data##a;e##b=data##b;
DD2(1,2) SORT2(1,2)
DD2(3,4) SORT2(3,4)
DD2(5,6) SORT2(5,6)
DD1(0) SORT2(0,2)
SORT2(3,5)
SORT2(4,6)
SORT2(0,1)
SORT2(4,5)
SORT2(2,6) CB1(6)
SORT2(0,4)
SORT2(1,5)
SORT2(0,3) CB1(0)
SORT2(2,5) CB1(5)
SORT2(1,3) CB1(1)
SORT2(2,4) CB1(4)
SORT2(2,3) CB2(2,3)
#undef CB1
#undef CB2
#undef DD1
#undef DD2
#undef SORT2
}
Take a look at this:
http://en.wikipedia.org/wiki/Sorting_algorithm
You would need to pick one that will have a stable worst case cost...
Another option could be to keep the array sorted the whole time, so an addition of a card would keep the array sorted automatically, that way you could skip to sorting...
What JRL is referring to is a bucket sort. Since you have a finite discrete set of possible values, you can declare 52 buckets and just drop each element in a bucket in O(1) time. Hence bucket sort is O(n). Without the guarantee of a finite number of different elements, the fastest theoretical sort is O(n log n) which things like merge sort an quick sort are. It's just a balance of best and worst case scenarios then.
But long answer short, use bucket sort.
If you like the above mentioned suggestion to keep a 52 element array which always keeps your array sorted, then may be you could keep another list of 7 elements which would reference the 7 valid elements in the 52 element array. This way we can even avoid parsing the 52 element array.
I guess for this to be really efficient, we would need to have a linked list type of structure which be supports operations: InsertAtPosition() and DeleteAtPosition() and be efficient at that.
There are a lot of loops in the answers. Given his speed requirement and the tiny size of the data set I would not do ANY loops.
I have not tried it but I suspect the best answer is a fully unrolled bubble sort. It would also probably gain a fair amount of advantage from being done in assembly.
I wonder if this is the right approach, though. How are you going to analyze a 7 card hand?? I think you're going to end up converting it to some other representation for analysis anyway. Would not a 4x13 array be a more useful representation? (And it would render the sorting issue moot, anyway.)
Considering that last 5 elements are always sorted:
for i := 0 to 1 do begin
j := i;
x := array[j];
while (j+1 <= 6) and (array[j+1] < x) do begin
array[j] := array[j+1];
inc(j);
end;
array[j] := X;
end;
bubble sort is your friend. Other sorts have too many overhead codes and not suitable for small number of elements
Cheers
Here is your basic O(n) sort. I'm not sure how it compares to the others. It uses unrolled loops.
char card[7]; // the original table of 7 numbers in range 0..51
char table[52]; // workspace
// clear the workspace
memset(table, 0, sizeof(table));
// set the 7 bits corresponding to the 7 cards
table[card[0]] = 1;
table[card[1]] = 1;
...
table[card[6]] = 1;
// read the cards back out
int j = 0;
if (table[0]) card[j++] = 0;
if (table[1]) card[j++] = 1;
...
if (table[51]) card[j++] = 51;
If you are looking for a very low overhead, optimal sort, you should create a sorting network. You can generate the code for a 7 integer network using the Bose-Nelson algorithm.
This would guarentee a fixed number of compares and an equal number of swaps in the worst case.
The generated code is ugly, but it is optimal.
Your data is in a sorted array and I'll assume you swap the new two if needed so also sorted, so
a. if you want to keep it in place then use a form of insertion sort;
b. if you want to have it the result in another array do a merging by copying.
With the small numbers, binary chop is overkill, and ternary chop is appropriate anyway:
One new card will mostly like split into two and three, viz. 2+3 or 3+2,
two cards into singles and pairs, e.g. 2+1+2.
So the most time-space efficient approach to placing the smaller new card is to compare with a[1] (viz. skip a[0]) and then search left or right to find the card it should displace, then swap and move right (shifting rather than bubbling), comparing with the larger new card till you find where it goes. After this you'll be shifting forward by twos (two cards have been inserted).
The variables holding the new cards (and swaps) should be registers.
The look up approach would be faster but use more memory.

Resources