C++ Classes: Christian Holiday Calculator - c++

Basically, I'm trying to complete this exam-style question for exam practice. I know how to do everything but the last question, to do with classes. I kinda get them, but don't know how to apply it to the question. Could anybody give me some starting points or tips (or even possible answers) to how I would go about creating a C++ class? Any help is much appreciated. The question is below. Apologies about how long it is.
In 1800 the mathematician Carl Friedrich Gauss presented an algorithm for calculating the
date of the Easter holiday in the new Gregorian calendar (introduced in the British Empire in
the year 1752). For this a number of expressions need to be evaluated:
Two terms M and N, which for a given year y hold the values:
year M N
1700-1799 23 3
1800-1899 23 4
1900-2099 24 5
2100-2199 24 6
The expressions are:
a = y mod 19
b = y mod 4
c = y mod 7
d = (19a + M) mod 30
e = (2b + 4c + 6d + N) mod 7
If 22+d+e is smaller than 32 than this sum is the day of the Easter holiday in March.
Otherwise d+e-9 is the day of Easter in April unless:
- the result is the 26th April, in which case Easter is on the 19th April instead
- the result is the 25th April, in which case Easter is on the 18th of April if d is 28 and
a is greater than 10
a) Implement a C/C++ function that given a year as parameter will
print out the date for the Easter holiday. (10 marks)
Other Christian holidays can be calculated from the date of Easter:
Good Friday is the Friday before Easter Sunday.
Palm Sunday is the Sunday before Easter Sunday.
Whit Sunday is 7 weeks after Easter Sunday.
Ascension day is 10 days before Whit Sunday.
Note: April and June are 30 days long, whereas March and May are 31 days long.
b) Design/describe algorithms for identifying the date for the Christian
holidays "Good Friday", "Palm Sunday", "Ascension" and "Whit
Sunday". (no source code is required for this answer) (15 Marks)
The terms M and N in the Easter calculation algorithm described by Gauss can also
be calculated using the following expressions:
k = floor(y/100)
p = floor((13 + 8k)/25)
q = floor(k/4)
M = (15 − p + k − q) mod 30
N = (4 + k − q) mod 7
The floor function rounds down a value – in the maths library math.h this is
available as a C function with the prototype double floor(double);
c) Produce a C++ class to implement a Christian Holiday calculator. It
should have private attributes (member variables) representing the
day, month and year of the date and a private method for
calculating the terms M and N. The default constructor should set
all attributes to 0. It should be possible to change the year using a
set() method and to retrieve day and month using get() methods.
The class should also contain compute methods for the different
holidays – example: computeEaster().

...how I would go about creating a C++ class?
Creating a class is simple:
class foobar
{
public:
private:
};
There! you now have a class foobar. That class can be whatever you want it to be. Fill in the public and private sections as appropriate.
Could anybody give me some starting points or tips...
As for how to use classes on how to solve a given problem, here are the general steps in roughly sequential order:
Identify the requirements of the problem. What needs solving?
Reform those requirements as a list of responsibilities. What does your program have to do to fulfill those requirements?
Group those responsibilities together to form a cohesive class object. How does this class object contribute to the overall solution of the problem? How will this object actually be used?
Express and capture that usage in a unit test for each of those objects. While doing this, you can pretend that that class is already implemented and whatever member functions you need from it is available.
Finally, implement that class so the unit test passes.
One last note, as David's comment already pointed out, copying and pasting the original problem verbatim into your question is a bad idea. People will be (substantially) less inclined to read it through. You can increase the likelihood for a response if you clarified exactly what trouble you're having and cutting out all the irrelevant parts.

So, you are stuck on creating a class. Either you don't know how to create a class at all, or you don't know how to create this specific class.
To create a class at all, use the class keyword: class { int i; };. If you have not yet created any classes in C++, then you may need to retake this or another C++ programming class.
If your problem, instead, is that you don't understand how to translate your professor's class design into C++ code, then you are not nearly as alone as you feel. Translating from ambiguous English design statements to concrete C++ programs is difficult, and is the reason we get paid the big bucks.
Let's go through it step by step.
Produce a C++ class to implement a Christian Holiday calculator.
That sounds easy enough, doesn't it?
class ChristianHolidayCalculator {
};
There, that step is done!.
It should have private attributes (member variables) representing the day, month and year of the date
Do you know what attributes or member variables are? Do you need to check the index of your textbook? Go ahead, I'll wait. ... Oh, you're back! You must have seen that member variables are a collection of variables which are scoped by the class declaration and which spring into existence (as a group) everytime an object of that class is created.
class ChristianHolidayCalculator {
double width;
double height;
double depth;
};
Oh, you thought I would name them "year", "month", and "day"? No, that's your homework, not mine. Since you told us that you know how to do the math, I'll leave the specifics to you.
and a private method for calculating the terms M and N.
There are two more vocabulary words: method and private. Go review your course material for those.
You surely found that a method is a function inside the class scope. Methods are special in that they are invoked only in relation to objects of the class at hand.
As for "private", well, I'll leave that to you. Surely you learned something about classes this year?
class ChristianHolidayCalculator {
double width;
double height;
double depth;
void GuitarTune() {
// Code to tighten strings goes here.
}
};
Since this method has to compute M and N, you'll need someplace to store the results. Hmm, maybe you need more member variables?
Finally, your teacher mentioned set(), get() and compute() methods. This is his shorthand way of telling you which public methods to create. He probably doesn't mean literally int get() { ... }. He probably means that you need to create a group of methods, all similar in name and in design:
class ChristianHolidayCalculator {
double width;
double height;
double depth;
void GuitarTune() {
// Code to tighten strings goes here.
}
int getRed() { /* return red value */ }
int getGreen() { /* return green value */ }
int getBlue() { /* return blue value */ }
void setRed(int newRed) { /* assign red value */ }
void setGreen(int newGreen) { /* guess */ }
... calculateEaster() ... { ... }
};
There is how you start to create the class. I hope this gives the push you need to get started. Good luck on your exams.

Related

Optimising usage of a frequently repopulated std::list<Class*> object in C++

OK, this is going to be a rather long question, because the issue might relate to the broader structure/organization of my code, rather than a specific line. Thanks in advance for those willing to take a look!
Model structure I have a computational biological model written in C++ which consists of multiple classes written in separate header and source files. I will try to simplify the problem as much as possible. Relevant here is that there are biol. cells (class Cell; see below if you prefer reading code), which have two compartments, A and B (i.e. two objects of class Compartment), each of which has a genome, G (i.e. single object of class Genome). Finally, the genome defines two lists of genes (pointers to Gene class). GeneList simply stores all genes that make up the genome (i.e. the essence of a genome). The second list, ExpressedGenes, contains only genes that are expressed, and this is what my question revolves around.
//simplification of Cell.hh
class Cell
{
public:
Compartment *A, *B;
};
//simplification of Compartment.hh
class Compartment
{
public:
Genome *G;
};
//simplification of Genome.hh
class Genome
{
public:
std::list<Gene*>* GeneList;
std::list<Gene*>* ExpressedGenes;
};
//simplification of Gene.cc
class Gene
{
public:
//...
int expression;
};
Model description To simulate a cell's behaviour, the core of what the model needs to do is calculate which genes become expressed the next timestep (expression set to 0 or 1), based on what genes are expressed during the current timestep. But, gene expression in say compartment A is not only determined by the genes in compartment A's genome, but also by those in compartment B's genome. We imagine that with a small probability the product of an expressed gene can be transported to the other compartment, influencing the subsequent gene expression in that compartment. Again, simplified, the entire update of a cell then appears in the following way.
//inside Cell.cc
Cell::UpdateCompartments()
{
std::list<Gene*>::iterator it;
A->G->NativeExpression(); //Create ExpressedGenes of A; see below.
B->G->NativeExpression(); //Create ExpressedGenes of B.
Transport(); //Potential movement (by splicing) of elements in ExpressedGenes of A to ExpressedGenes of B, and vice versa.
A->G->UpdateGeneExpression(); //Use ExpressedGenes of A to update expression for each gene in GeneList of A.
it = A->G->ExpressedGenes->erase(A->G->ExpressedGenes->begin(), A->G->ExpressedGenes->end()); //Erase ExpressedGenes of A, gene expression has been stored in the gene objects.
B->UpdateGeneExpression(); //Same but for B.
it = B->G->ExpressedGenes->erase(B->G->ExpressedGenes->begin(), B->G->ExpressedGenes->end());
}
//inside Genome.cc
void Genome::NativeExpression()
{
std::list<Gene*>::iterator it;
//Iterate through GeneList, if we find a gene that is expressed, store a pointer to it in ExpressedGenes.
it = GeneList->begin();
while (it != GeneList->end())
{
if ((*it)->kind==REGULATOR || (*it)->kind==EFFECTOR)
{
Gene* gene = dynamic_cast<Gene*>(*it);
if(gene->expression > 0) ExpressedGenes->push_back(gene);
}
it++;
}
}
Problem statement The problem is that the boring little piece of code above (i.e. the function NativeExpression) costs more time than anything else in the model (see results from GPROF analysis below). This seems weird to me because, ExpressedGenes being a list of pointers should not be so much overhead right? And I am just creating pointers to existing Gene objects, and removing them later... As shown by the GPROF output, time is largely wasted during the function itself (220.01s), not by any of the calls within it (i.e. iterating through the list, checking elements, adding new elements; total of 28.92s). Furthermore, I found no difference in the time profile when I replaced the dynamic_cast with a static_cast. These points lead me to believe that the inefficiency might be in the broader structure of my classes, or in how I use pointers between them. So, suggestions or other remarks will be much appreciated.
...

Optimising comparisons of boolean arrays in C++

I am trying to improve the speed of a computational (biological) model written in C++ (previous version is on my github: Prokaryotes). The most time-consuming function is where I calculate binding affinities between transcription factors and binding sites on a single genome.
Background: In my model, binding affinity is given by the Hamming distance between the binding domain of a transcription factor (a 20-bool array) and the sequence of a binding site (also a 20-bool array). For a single genome, I need to calculate the affinities between all active transcription factors (typically 5-10) and all binding sites (typically 10-50). I do this every timestep for more than 10,000 cells in the population to update their gene expression states. Having to calculate up to half a million comparisons of 20-bool arrays to simulate just one timestep of my model means that typical experiments take several months (2M--10M timesteps).
For the previous version of the model (link above) genomes remained fairly small, so I could calculate binding affinities once for every cell (at birth) and store and re-use these numbers during the cell's lifetime. However, in the latest version, genomes expand considerably and multiple genomes reside within the same cell. Thus, storing affinities of all transcript factor--binding site pairs in a cell becomes impractical.
In the current implementation I defined an inline function belonging to the Bead class (which is a base class for transcription factor class "Regulator" and binding site class "Bsite"). It is written directly in the header file Bead.hh:
inline int Bead::BindingAffinity(const bool* sequenceA, const bool* sequenceB, int seqlen) const
{
int affinity = 0;
for (int i=0; i<seqlen; i++)
{
affinity += (int)(sequenceA[i]^sequenceB[i]);
}
return affinity;
}
The above function accepts two pointers to boolean arrays (sequenceA and sequenceB), and an integer specifying their length (seqlen). Using a simple for-loop I then check at how many positions the arrays differ (sequenceA[i]^sequenceB[i]), summing into the variable affinity.
Given a binding site (bsite) on the genome, we can then iterate through the genome and for every transcription factor (reg) calculate its affinity to this particular binding site like so:
affinity = (double)reg->BindingAffinity(bsite->sequence, reg->sequence);
So, this is how streamlined I managed to make it; since I don't have a programming background, I wonder whether there are better ways to write the above function or to structure the code (i.e. should BindingAffinity be a function of the base Bead class)? Suggestions are greatly appreciated.
Thanks to #PaulMcKenzie and #eike for your suggestions. I tested both ideas against my previous implementation. Below are the results. In short, both answers work very well.
My previous implementation yielded an average runtime of 5m40 +/- 7 (n=3) for 1000 timesteps of the model. Profiling analysis with GPROF showed that the function BindingAffinity() took 24.3% of total runtime. [see Question for the code].
The bitset implementation yielded an average runtime of 5m11 +/- 6 (n=3), corresponding to a ~9% speed increase. Only 3.5% of total runtime is spent in BindingAffinity().
//Function definition in Bead.hh
inline int Bead::BindingAffinity(std::bitset<regulator_length> sequenceA, const std::bitset<regulator_length>& sequenceB) const
{
return (int)(sequenceA ^= sequenceB).count();
}
//Function call in Genome.cc
affinity = (double)reg->BindingAffinity(bsite->sequence, reg->sequence);
The main downside of the bitset implementation is that unlike with boolean arrays (my previous implementation), I have to specify the length of the bitset that goes into the function. I am occasionally comparing bitsets of different lengths, so for these I now have to specify separate functions (templates would not work for multi-file project according to https://www.cplusplus.com/doc/oldtutorial/templates/).
For the integer implementation I tried two alternatives to the std::popcount(seq1^seq2) function suggested by #eike since I am working with an older version of C++ that doesn't include this.
Alternative #1:
inline int Bead::BindingAffinity(int sequenceA, int sequenceB) const
{
int i = sequenceA^sequenceB;
std::bitset<32> bi (i);
return ((std::bitset<32>)i).count();
}
Alternative #2:
inline int Bead::BindingAffinity(int sequenceA, int sequenceB) const
{
int i = sequenceA^sequenceB;
//SWAR algorithm, copied from https://stackoverflow.com/questions/109023/how-to-count-the-number-of-set-bits-in-a-32-bit-integer
i = i - ((i >> 1) & 0x55555555); // add pairs of bits
i = (i & 0x33333333) + ((i >> 2) & 0x33333333); // quads
i = (i + (i >> 4)) & 0x0F0F0F0F; // groups of 8
return (i * 0x01010101) >> 24; // horizontal sum of bytes
}
These yielded average runtimes of 5m06 +/- 6 (n=3) and 5m06 +/- 3 (n=3), respectively, corresponding to a ~10% speed increase compared to my previous implementation. I only profiled Alternative #2, which showed that only 2.2% of total runtime was spent in BindingAffinity(). The downside of using integers for bitstrings is that I have to be very careful whenever I change any of the code. Single-bit mutations are definitely possible as mentioned by #eike, but everything is just a little bit trickier.
Conclusion:
Both the bitset and integer implementations for comparing bitstrings achieve impressive speed improvements. So much so, that BindingAffinity() is no longer the bottleneck in my code.

About time complexity of this recurrence relation after memoizing it

I solved a question on LeetCode.com with some online help:
There are 2N people a company is planning to interview. The cost of flying the i-th person to city A is costs[i][0], and the cost of flying the i-th person to city B is costs[i][1]. Return the minimum cost to fly every person to a city such that exactly N people arrive in each city.
as:
class Solution {
public:
int helper(vector<vector<int>>& c, vector<vector<int>>& dp, int start, int a, int b) {
if((a>c.size()/2) || (b>c.size()/2)) return INT_MAX/2;
if(a+b==(int)c.size()) return 0;
if(dp[a][b]!=-1) {
return dp[a][b];
}
int minA=c[start][0]+helper(c, dp, start+1, a+1, b);
int minB=c[start][1]+helper(c, dp, start+1, a, b+1);
int minVal=min(minA, minB);
dp[a][b]=minVal;
return minVal;
}
int twoCitySchedCost(vector<vector<int>>& costs) {
vector<vector<int>> dp(costs.size()+1, vector<int>(costs.size()+1, -1));
int minCost=helper(costs, dp, 0, 0, 0);
return minCost;
}
};
Without the dp table, using the Subtract-and-Conquer Recurrence method (courtesy of this answer, I came up with the time complexity of the recursive solution as O(n) where n is the total number of people (a=b=1 and k=0).
However, I am unsure how to derive the time complexity now, with the inclusion of the dp table. I am confused because, AFAIK, how many times the cached values would be used depends upon the specific problem instance (value of n i.e., the size of the costs table). Obviously the time complexity has improved (since we have cached the results of the overlapping sub-problems) hasn't it?
How can I derive this?
Edit
As I notice this again, I realize that I made a mistake in calculating the time complexity above - my a is not 1, it is 2. Which brings the time complexity to be O(2^n).
As a rule of thumb that you can almost always rely on, the time complexity of a DP is O(size of DP Table * O(transition)). This is because you can assume getting the memory for your DP Table is time itself, not to mention the fact that you, in most cases, would have the possibility to visit all of those states. For most problems, if you don't visit a systematic majority of your states given worst-case input, your state can be reduced. But I digress.
For this specific problem, your runtime would be O(costs.size()^2), since your transition looks O(1) and your memo table is O(costs.size()^2)
Also, just a nice thing that i like to do is return dp[i][j]=minVal. And in general, return dp[state] = returnval is helpful because you know you didn't forget to memoise. Best of luck!

Dynamic Array & Class Inheritance

I am doing a homework assignment for my summer OO class and we need to write two classes. One is called Sale and the other is called Register. I've written my Sale class; here's the .h file:
enum ItemType {BOOK, DVD, SOFTWARE, CREDIT};
class Sale
{
public:
Sale(); // default constructor,
// sets numerical member data to 0
void MakeSale(ItemType x, double amt);
ItemType Item(); // Returns the type of item in the sale
double Price(); // Returns the price of the sale
double Tax(); // Returns the amount of tax on the sale
double Total(); // Returns the total price of the sale
void Display(); // outputs sale info
private:
double price; // price of item or amount of credit
double tax; // amount of sales tax
double total; // final price once tax is added in.
ItemType item; // transaction type
};
For the Register class we need to include a dynamic array of Sale objects in our member data.
So my two questions are:
Do I need to inherit from my Sale class into my Register class (and if so, how)?
Can I have a generic example of a dynamic array?
Edit: We cannot use vectors.
No inheritance is required. A generic example:
std::vector<Sale> sales;
Gotta love templates.
No, inheritance would not be appropriate in this case. You would want to keep track of the number of sales and the size of the array as fields in the Register class. The class definition would include this
class Register{
private:
int numSales;
int arraySize;
Sale* sales;
public:
Register();
~Register();
void MakeSale(Sale);
};
Register::Register(){
numSales = 0;
arraySize = 5;
sales = new Sale[arraySize];
}
void Register::MakeSale(Sale s){
if(numSales == arraySize){
arraySize += 5;
Sale * tempArray = new Sale[arraySize];
memcpy(tempArray, sales, numSales * sizeof(Sale));
delete [] sales;
sales = tempArray;
}
sales[numSales] = s;
++numSales;
}
Register::~Register()
{
delete [] sales;
}
This doesn't include bounds checking or whatever other stuff you need to do when you make a sale, but hopefully this should help.
If you CANNOT use vectors, then you can use a std::list. You really should use standard containers as much as possible - chances are that any home-rolled solution will be inferior. The standard library is extensively optimized and tested - do you really feel the need to make the same investment when you have better things to be doing than reinventing the wheel?
std::list should not allocate more space than necessary. However, it has some serious limitations. The fact that a vector and other forms of dynamic array is contiguous gives large performance advantages.
Not being able to use vectors seems like a very arbitrary limitation. The fact that they allocate more space than necessary is a feature, not a bug. It allows the container to amortize the expensive copy and/or move operations involved in a reallocation. An intelligent vector implementation should check for low memory situations and handle those gracefully. If it doesn't, you should submit patches to your standard library implementation or move to a new one. But imposing arbitrary constraints with no explanation, e.g.:
There should never be more than 5 unused slots in this array (i.e. the
number of allocated spaces may be at most 5 larger than the number of
slots that are actually filled with real data).
is bad practice. And where did the number FIVE come from? It's not even a power of two! If you want to hack around this limitation using std::vector::reserve, that's probably your best bet. But all that book-keeping should not need to be done.
And, agreed with everyone else: inheritance is not what you want here.

How to get through the 120 bytes limit?

This is actually a SPOJ problem: WAYS
Now this is a very easy task what we need to do is to compute the Central binomial coefficients.
However the problem setter includes a very notorious source limit of 120 bytes, so my question is how to get past that source code limit in the languages that are allowed?
Assuming, that C(2n,n) = (2n)!/(n!)^2 = (2n(2n-1)/n^2) * C(2(n-1),n-1) = ((4n-2)/n)*C(2(n-1),n-1) here is function, which calculates central binomial:
int f(int n)
{
return n==1? 2 : f(n-1)*(4*n-2)/n;
}
Edit: Here is probably shortest code:
int f(int n){return n<2?2:f(n-1)*(4*n-2)/n;}
It is only 44 characters.
I haven't tried writing the code, but since the value of m is only 14, you could submit a table. Not sure if the code can be made shorter than this.