I am using a couple of structs in my code. The first struct is constructed after reading data from a line of text file and the second struct contains a vector of structs of the first kind.
struct A{
long a, b, c, d, e, f;
string x, y, z;
}
struct B{
string id1;
vector<A> aVec;
}
Now I read my file and initialize a vector of struct B's. Then based on what the incoming new line's id1 and id2 are, I create a new A and push it into the correct B.
vector<B> bVec;
vector<A> atmpVec;
B btmp;
//Initializing bVec
for(int i = 0; i < 7; i++)
{
btmp.id1 = "c"+to_string(i);
btmp.aVec = atmpVec;
//tried using reserve too.
//btmp.aVec.reserve(50000);
bVec.push_back(btmp);
}
//readerCode
while(getline(file, line))
{
A = readA(line); //readA reads and sets the fields of struct A.
int idx = getBIdx(bVec, A); //getBIdx returns which B struct should i be using.
bVec[idx].aVec.push_back(A);
}
Now the last line has become a bottleneck. If I simply declare a vector of A and keep on pushing back to it, the time taken to process a million records is ~10 seconds.
On the other hand, with this approach, it takes 60 seconds to just process 50k records.
Is there a way I can keep the above general structure without losing the performance.
Any ways to efficiently implement this?
Isn't the time spent in the getBIdx method ? Pushing to a single vector or one between N should be almost the same.
Trying with a simple getBIdx:
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
#include <time.h>
using namespace std;
const int NUMBER_OF_A = 3E7;
const int NUMBER_OF_B = 7;
struct A {
long a, b, c, d, e, f;
string x, y, z;
};
struct B {
string id1;
vector<A> aVec;
};
struct A readA() {
A a;
a.a = 1;
a.b = 2;
return a;
}
int getBIdx(const A& a) {
return rand() % NUMBER_OF_B;
}
void Test1() {
vector<B> bVec;
for(int i = 0; i < NUMBER_OF_B; i++) {
B btmp;
bVec.push_back(btmp);
}
for(int i = 0; i < NUMBER_OF_A; ++i) {
A a = readA();
int idx = getBIdx(a);
bVec[idx].aVec.push_back(a);
}
}
void Test2() {
vector<A> vector;
for(int i = 0; i < NUMBER_OF_A; ++i) {
A a = readA();
int idx = getBIdx(a);
vector.push_back(a);
}
}
int main() {
time_t start = time(0);
Test1();
time_t end_of_test1 = time(0);
Test2();
time_t end_of_test2 = time(0);
cout << "Elapsed test 1:" << end_of_test1 - start << " s" << endl;
cout << "Elapsed test 2:" << end_of_test2 - end_of_test1 << " s" << endl;
return 0;
}
Result: (old Pentium 4 single core machine)
Elapsed test 1:17 s
Elapsed test 2:13 s
So it's slower but not that slower.
With -O3 the difference is even smaller:
Elapsed test 1:9 s
Elapsed test 2:7 s
I would try to optimize this code in two ways
define vector<A*> aVec instead of vector<A> aVec, to avoid copy constructor call ,since you are using C++0x
estimate the size of size of aVec in B, using resize() to resever some space might save some time
You should probably using the sizing constructor on bVec as it's size is known.
Then for the main culprit of filling it with vector of A, you probably
want to use vector::reserve on each avec inside bVec with an arbitrary size depending on your number of data to be fed.
Also, are you sure you compile with -O3 ?
Related
I have several classes that capture are certain functionality and have a simply type member variable, e.g.
float m_a;
For all of these classes, I need now an additional version where this member is a nested vector of a such a simple type, e.g.
std::vector<std::vector<float>> m_a;
Size of the vectors is not known during compile time but constant during object lifetime. The remaining functionality stays the same, only that every access to m_a in the first case is replaced by a corresponding nested for-loop in the second case.
Obviously, the second case contains the first case as a special case by using vectors of size 1 (only m_a[0][0]).
This would save me writing several new classes with nearly identical behavior. However, objects of these classes are used (created and accessed) thousands to millions of times. So the question is, how critical is the memory and access overhead created by that?
Edit: I tried to test it with the following simplified program.
#include <vector>
#include <iostream>
class A{
public:
A(float a) : m_a(a) {};
float m_a;
};
class B{
public:
B(float b) : m_b({b}) {};
std::vector<float> m_b;
};
int main(int argc, char** argv){
unsigned numOfRuns = 10; // to average out random fluctuations
for(int r = 0; r < numOfRuns; r++){
unsigned n = atoi(argv[1]);
std::vector<A> a; // simple type
a.reserve(n);
clock_t ta1 = clock();
for(int i=0; i<n; i++){
a.emplace_back( A(i) ); // create
}
clock_t ta2 = clock();
std::vector<B> b; // 1-element array
b.reserve(n);
clock_t tb1 = clock();
for(int i=0; i<n; i++){
b.emplace_back( B(i) ); // create
}
clock_t tb2 = clock();
clock_t ta3 = clock();
for(int i=0; i<n; i++){
a[i].m_a; // access
}
clock_t ta4 = clock();
clock_t tb3 = clock();
for(int i=0; i<n; i++){
b[i].m_b[0]; // access
}
clock_t tb4 = clock();
std::cout << n << "\t" << ((tb2-tb1)/(float)(ta2-ta1)) << "\t" << ((tb4-tb3)/(float)(ta4-ta3)) << std::endl;
}
return 0;
}
According to this, creation takes 13x more time and access 1.8x more. I also checked briefly the memory consumption, which was nearly a factor of 10 larger for n=10000000.
Unless I made some stupid mistake, this is really surprising for me. I expected some overhead but not an order of magnitude more memory and time consumption.
i searched a lot here, but there is no right explanation for me, for an advanced newbie in c++. I worked before with vector of structs and now I get segmentation faults...
Thats why I want to know how such objects actually works and if it is the right the way I am doing!
I have a struct like
struct numberOfSpecies {
int predator;
int prey1;
int prey2;
};
and a vector of it:
std::vector<numberOfSpecies> size;
Before I resize it and fill it with values.
size.resize(100);
what is actually this doing? Is this right for a struct?
It looks like it is initialized with zeros...
Now I am doing this like:
size[t].predator=0;
size[t].prey1=0;
size[t].prey2=0;
for(int k = 0; k < N; ++k){
size[t].predator++;
size[t].prey1++;
size[t].prey2++;
}
Is this right? Where are possible issues? How to do it better?
The easiest and 'correct' solution here is probably to just use the resize() function that belongs to the vector object with aggregate initialization (if you have access to c++11 and on), something like
size.resize(100,{0,0,0}); //aggregate initialization
for(int k = 0; k < N; ++k)
{
size[t].predator++;
size[t].prey1++;
size[t].prey2++;
}
All members of each numberOfSpecies object will be initialized to 0.
This:
size[t].predator=0;
size[t].prey1=0;
size[t].prey2=0;
will write zeros to the tth element of size - that may or may not be useful:
This:
for(int k = 0; k < N; ++k){
size[t].predator++;
size[t].prey1++;
size[t].prey2++;
}
will increment the tth element of size N times. This seems incredibly unlikely to be useful. I think what you want is:
size[0].predator=0; // Technically not needed because .resize()
size[0].prey1=0; // will have initialized it to zero anyway
size[0].prey2=0; // *BUT* explicit is always better than implicit.
// Initialize each element of size to be one greater than previous.
for(int k = 1; k < N; ++k){
size[k].predator = size[k-1].predator + 1;
size[k].prey1 = size[k-1].prey1 + 1;
size[k].prey2 = size[k-1].prey2 + 1;;
}
Use the value parameter for static parameters.
#include <vector>
struct foo{
int g;
int h;
int l;
};
int main()
{
std::vector<foo> manyFoo(10, {0});
manyFoo.resize(60, {0});
}
If you want to grow your vector as you also put arbitrary values into the struct you could ->
#include <iostream>
#include <vector>
struct foo{
foo(int aG,int aH, int aL):g(aG),h(aH),l(aL) {};
int g;
int h;
int l;
};
int main() {
std::vector<foo> lVec;
for (int i=0;i<10;i++) {
lVec.emplace_back(foo(i,i*2,i*4));
}
int lPos=0;
for (auto &rFoo: lVec) {
std::cout << "Item pos" << lPos++ << " g:" << rFoo.g << " h:" << rFoo.h << " l:" << rFoo.l << std::endl;
}
return EXIT_SUCCESS;
}
If you know the size of the vector and you want to populate it you could ->
#include <iostream>
#include <vector>
struct foo{
foo(int aG,int aH, int aL):g(aG),h(aH),l(aL) {};
int g;
int h;
int l;
};
int main() {
std::vector<foo> lVec(10,{0,0,0});
int lPos = 0;
for (auto &rFoo: lVec) {
rFoo = foo(lPos,lPos*2,lPos*4);
lPos++;
}
lPos=0;
for (auto &rFoo: lVec) {
std::cout << "Item pos" << lPos++ << " g:" << rFoo.g << " h:" << rFoo.h << " l:" << rFoo.l << std::endl;
}
return EXIT_SUCCESS;
}
You could add an default constructor to your structure. The new code will look something like this:
struct numberOfSpecies {
numberOfSpecies (): predator(0), prey1(0), prey2(0) { } // default constructor
int predator;
int prey1;
int prey2;
};
That way, your structure will be properly initialized inside your vector when resize is applied.
Let see code:
struct tmp {
int a;
std::vector <second_struct> b;
}
struct second_struct {
int x;
int y;
}
//main.cpp
int main {
std::vector<tmp> test;
(...); //push data to test
}
So when i push data to test, in second function i want to get vector "b" from this vector 'test'. And find vector b by a;
(i.e I have int a and std::vector<tmp> test; , dont have std::vector <second_struct> b;(from vector test) and want to get it. (vector test is a big array, so i need to do it fastest and using little power )
How to do that? (i suppose std::map will be better? But if you tell me yes, tell me too how to do that in std::Vector)
Loop through test vector checking if tmp::a member is equal to your int a. If so, you have your vector<second_struct> b
for (int i=0;i<test.size();i++) {
if (test[i].a == a) {
// do whatever you need to do with test[i].b
break;
}
}
P.S. map would be easier, just
std::map<int, std::vector<second_struct>> map;
//insert data
std::vector<second_struct> b = map[a]; //assuming it's a that you're looking for
The most straightforward approach is to use map (or unordered_map in C++11). Hope this full example helps:
#include <map>
#include <vector>
#include <iostream>
struct str {
str(int _x, int _y) : x(_x), y(_y) {}
int x, y;
};
std::map<int, std::vector<str> > test;
int main() {
std::vector<str> vec;
for (int i = 0; i < 100; ++i) {
vec.clear();
vec.push_back(str(i, 2 * i));
vec.push_back(str(i + 1, i + 2));
test[i] = vec;
}
std::vector<str> result;
// get some element
result = test[10];
std::cout << "Found at position 10:\n";
for (int i = 0; i < result.size(); ++i)
std::cout << result[i].x << ' ' << result[i].y << '\n';
return 0;
}
Why does this program write 45, 125 and 300?
I know for 45 and 300, I'm more interested in a case sum1(arrD), where program writes 125.
I hope somebody will know.
#include <iostream>
using namespace std;
class B{
public:
B(): b(bCounter++){}
int b;
static int bCounter;
};
int B::bCounter = 0;
class D : public B{
public:
D() : d(bCounter){}
int d;
};
const int N = 10;
B arrB[N];
D arrD[N];
int sum1(B* arr){
int s = 0;
for (int i=0; i<N; i++) s+=arr[i].b;
return s;
}
int sum2 (D* arr){
int s = 0;
for (int i = 0; i<N; i++) s+= arr[i].b + arr[i].d;
return s;
}
int main(){
cout<<" result is: "<<sum1(arrB)<<endl;
cout<<" result is: "<<sum1(arrD)<<endl;
cout<<" result is: "<<sum2(arrD)<<endl;
system("pause");
return 0;
}
The static arrays B arrB[N] and D arrD[N] seem to be causing the trouble here.
Arrays aren't polymorphic; you can pass a D* to a function expecting a B* only if it expects a single element. (Try using std::vector, and you'll get a compile time error.) The reason is simple: the pointer arithmetic needed to access the array elements is based on the static size of the pointed to element, so each time you do i++ in the loop in sum1, and then index, the compiler calculates the address of your element as arr + i * sizeof(B) (at the machine level, where arr is a pure, untyped address).
Trying to do pointer arithmetic when the static type is not the same as the dynamic type is undefined behavior, so as far as the language is concerned, anything can happen.
And this is yet another reason not to use C style arrays.
The problem is that the arrays do not contain pointers to the objects but whole objects.
So when you use the D array via a pointer to the base class, (as James noted) the behaviour is undefined.
What in practice probably happens on most systems: The pointer-based loop only iterates over half the D objects, because a B object contains only one int, while the D objects contain two of them.
So the loop looks only at the first 5 D objects:
b / d
10/11
11/12
12/13
13/14
14/15
which sums up to the ominous 125.
I think it's incorrect to cast an array of D to an array of B. The stride isn't correct. This is why you see these repeats of values.
Run following code , you'll know the reason
#include <iostream>
using namespace std;
class B{
public:
B(): b(bCounter++){
cout<<"B called\n";
}
int b;
static int bCounter;
};
int B::bCounter = 0;
class D : public B{
public:
D() : d(bCounter){
cout<<"D called\n";
}
int d;
};
const int N = 10;
B arrB[N];
D arrD[N];
int sum1(B* arr){
int s = 0;
for (int i=0; i<N; i++)
{
cout<<arr[i].b<<"\n";
s+=arr[i].b;
}
return s;
}
int sum2 (D* arr){
int s = 0;
for (int i = 0; i<N; i++) s+= arr[i].b + arr[i].d;
return s;
}
int main(){
//cout<<" result is: "<<sum1(arrB)<<endl;
cout<<" result is: "<<sum1(arrD)<<endl;
//cout<<" result is: "<<sum2(arrD)<<endl;
system("pause");
return 0;
}
I am trying to write a program with a function double_product(vector<double> a, vector<double> b) that computes the scalar product of two vectors. The scalar product is
$a_{0}b_{0}+a_{1}b_{1}+...+a_{n-1}b_{n-1}$.
Here is what I have. It is a mess, but I am trying!
#include <iostream>
#include <vector>
using namespace std;
class Scalar_product
{
public:
Scalar_product(vector<double> a, vector<double> b);
};
double scalar_product(vector<double> a, vector<double> b)
{
double product = 0;
for (int i = 0; i <= a.size()-1; i++)
for (int i = 0; i <= b.size()-1; i++)
product = product + (a[i])*(b[i]);
return product;
}
int main() {
cout << product << endl;
return 0;
}
Unless you need to do this on your own (e.g., writing it is homework), you should really use the standard algorithm that's already written to do exactly what you want:
#include <iostream>
#include <numeric>
#include <vector>
int main() {
std::vector<double> a {1, 2, 3};
std::vector<double> b {4, 5, 6};
std::cout << "The scalar product is: "
<< std::inner_product(std::begin(a), std::end(a), std::begin(b), 0.0);
return 0;
}
Note that while begin(a) and end(a) are new in C++11, std::inner_product has been available since C++98. If you are using C++ 98 (or 03), it's pretty easy to write your own equivalent of begin and end to work with arrays though:
template <class T, size_t N>
T *begin(T (&array)[N]) {
return array;
}
template <class T, size_t N>
T *end(T (&array)[N]) {
return array + N;
}
Using these, a C++ 98 version of the previous code could look something like this:
int main() {
double a[] = {1, 2, 3};
double b[] = {4, 5, 6};
std::cout << "The scalar product is: "
<< std::inner_product(begin(a), end(a), begin(b), 0.0);
return 0;
}
Note that the begin and end above will only work for arrays, where the begin and end in C++11 (and later) will also work for normal collection types that define a .begin() and .end() (though it's trivial to add overloads to handle those as well, of course):
template <class Coll>
typename Coll::iterator begin(Coll const& c) { return c.begin(); }
template <class Coll>
typename Coll::iterator end(Coll const& c) { return c.end(); }
You can delete the class you have defined. You don't need it.
In your scalar_product function:
double scalar_product(vector<double> a, vector<double> b)
{
double product = 0;
for (int i = 0; i <= a.size()-1; i++)
for (int i = 0; i <= b.size()-1; i++)
product = product + (a[i])*(b[i]);
return product;
}
It's almost there. You don't need 2 loops. Just one.
double scalar_product(vector<double> a, vector<double> b)
{
if( a.size() != b.size() ) // error check
{
puts( "Error a's size not equal to b's size" ) ;
return -1 ; // not defined
}
// compute
double product = 0;
for (int i = 0; i <= a.size()-1; i++)
product += (a[i])*(b[i]); // += means add to product
return product;
}
Now to call this function, you need to create 2 vector objects in your main(), fill them with values, (the same number of values of course!) and then call scalar_product( first_vector_that_you_create, second_vector_object );
While you have been presented many solutions that work, let me spin up another variation to introduce a couple of concepts that should help you writing better code:
class are only needed to pack data together
a function should check its preconditions as soon as possible, those should be documented
a function should have postconditions, those should be documented
code reuse is the cornerstone of maintenable programs
With that in mind:
// Takes two vectors of the same size and computes their scalar product
// Returns a positive value
double scalar_product(std::vector<double> const& a, std::vector<double> const& b)
{
if (a.size() != b.size()) { throw std::runtime_error("different sizes"); }
return std::inner_product(a.begin(), a.end(), b.begin(), 0.0);
} // scalar_product
You could decide to use the inner_product algorithm directly but let's face it:
it requires four arguments, not two
it does not check for its arguments being of the same size
so it's better to wrap it.
Note: I used const& to indicate to the compiler not to copy the vectors.
You seem to want to make a class specifically for vectors. The class I made in my example is tailored to 3 dimensional vectors, but you can change it to another if desired. The class holds i,j,k but also can conduct a scalar products based on other MathVectors. The other vector is passed in via a C++ reference. It is hard to deduce what the question was, but I think this might answer it.
#include <iostream>
using namespace std;
class MathVector
{
private:
double i,j,k;
public:
MathVector(double i,double j,double k)
{
this->i=i;
this->j=j;
this->k=k;
}
double getI(){return i;}
double getJ(){return j;}
double getK(){return k;}
double scalar(MathVector &other)
{
return (i*other.getI())+(j*other.getJ())+(k*other.getK());
}
};
int main(int argc, char **argv)
{
MathVector a(1,2,5), b(2,4,1);
cout << a.scalar(b) << endl;
return 0;
}
Here is the code that you should have. I see you have used class in your code, which you do not really need here. Let me know if the question required you to use class.
As you are new and this code might scare you. So, I will try to explain this as I go. Look for comments in the code to understand what is being done and ask if you do not understand.
//Scalar.cpp
#include <stdlib.h>
#include <iostream>
#include <vector>
using namespace std;
/**
This function returns the scalar product of two vectors "a" and "b"
*/
double scalar_product(vector<double> a, vector<double> b)
{
//In C++, you should declare every variable before you use it. So, you declare product and initialize it to 0.
double product = 0;
//Here you check whether the two vectors are of equal size. If they are not then the vectors cannot be multiplied for scalar product.
if(a.size()!=b.size()){
cout << "Vectors are not of the same size and hence the scalar product cannot be calculated" << endl;
return -1; //Note: This -1 is not the answer, but just a number indicating that the product is not possible. Some pair of vectors might actually have a -1, but in that case you will not see the error above.
}
//you loop through the vectors. As bobo also pointed you do not need two loops.
for (int i = 0; i < a.size(); i++)
{
product = product + a[i]*b[i];
}
//finally you return the product
return product;
}
//This is your main function that will be executed before anything else.
int main() {
//you declare two vectors "veca" and "vecb" of length 2 each
vector<double> veca(2);
vector<double> vecb(2);
//put some random values into the vectors
veca[0] = 1.5;
veca[1] = .7;
vecb[0] = 1.0;
vecb[1] = .7;
//This is important! You called the function you just defined above with the two parameters as "veca" and "vecb". I hope this cout is simple!
cout << scalar_product(veca,vecb) << endl;
}
If you are using an IDE then just compile and run. If you are using command-line on a Unix-based system with g++ compiler, this is what you will do (where Scalar.cpp is the file containing code):
g++ Scalar.cpp -o scalar
To run it simply type
./scalar
You should get 1.99 as the output of the above program.