patterncppMinor
Inner product of random floats written to file
Viewed 0 times
randomfilewrittenproductinnerfloats
Problem
My goals are to make this code:
What the code does:
Currently compiled with:
- faster
- more idiomatic C++
What the code does:
- take an integer command-line argument
N
- make a vector of
Nrandom floating point values
- make a matrix of
N*Nrandom floating point values
- do inner product of vector * matrix
- write the resulting vector to a file
Currently compiled with:
g++ myFile.cpp -std=c++11 -O3#include
#include
const std::string outputName = "output/coutput.txt"; // the name of the file this program makes
std::ostream& operator& v)
{ // pretty-print a vector of doubles using operator(RAND_MAX);
}
int main(int argc, char* argv[])
{
// file i/o
std::ofstream result;
result.open(outputName, std::ios::out);
srand(1);
long elems = std::atol(argv[1]); // command line param
std::vector m(elems * elems); // (elems * elems); // actually this is a vector of length (N*N)
std::vector a(elems);
std::vector r(elems, 0); // to store the result
for (auto i = 0; i < elems; i++) // generate random vector
a[i] = genRand();
for (auto i = 0; i < elems * elems; i++) // generate random matrix
m[i] = genRand();
for (auto i = 0; i < m.size(); i++) {
auto idx = i / a.size();
r[idx] += a[idx] * m[i];
}
result << r << std::endl; // print results
result.close();
}Solution
If you're going to use C++11, you should firstly look at throwing out
rand, and using the newer features found in `. The setup is a bit more complex, but the distributions are generally much better statistically. Also, instead of generating numbers one at a time, we're going to generate them in a batch:
template >
Cont generate_rand(std::size_t n)
{
Cont results;
results.reserve(n);
std::random_device rd;
std::mt19937 generator(rd());
std::uniform_real_distribution<> dist;
auto random = [&]() { return dist(generator); };
std::generate_n(std::back_inserter(results), n, random);
return results;
}
With this, we can generate a set of random values into a vector:
// Read into num however many values we want to generate from args
auto vec = generate_rand(num);
Working with an actual matrix is a bit easier, so let's generate that (instead of an n * n length vector):
std::vector> matrix;
for(auto i = 0; i < num; ++i) {
matrix.emplace_back(generate_rand(num));
}
Something to hold our results, with the size correctly reserved:
std::vector result;
result.reserve(num);
The algorithm library already has a function that will do what you want: std::inner_product:
for(auto it = matrix.begin(); it != matrix.end(); ++it) {
auto v = std::inner_product(std::begin(vec), std::end(vec), std::begin(*it), 0.0);
result.push_back(v);
}
Alternately, this is the place where a library like Eigen comes in really handy; with the correct includes, this can be written as follows:
#include
typedef Eigen::MatrixXd Dynamic2d;
int main()
{
// Initialize num from program args
auto x = Dynamic2d::Random(num, num);
auto y = Dynamic2d::Random(1, num);
auto res = y * x;
}
(Note however that Random gives a range between [-1, 1] when called like this, so you'd need to potentially do a bit of work to get that distribution back to [0, 1]`). This is likely to give you the maximum performance, as libraries like Eigen have had a lot of time spent on making them highly efficient.Code Snippets
template <typename Cont = std::vector<double>>
Cont generate_rand(std::size_t n)
{
Cont results;
results.reserve(n);
std::random_device rd;
std::mt19937 generator(rd());
std::uniform_real_distribution<> dist;
auto random = [&]() { return dist(generator); };
std::generate_n(std::back_inserter(results), n, random);
return results;
}// Read into num however many values we want to generate from args
auto vec = generate_rand(num);std::vector<std::vector<double>> matrix;
for(auto i = 0; i < num; ++i) {
matrix.emplace_back(generate_rand(num));
}std::vector<double> result;
result.reserve(num);for(auto it = matrix.begin(); it != matrix.end(); ++it) {
auto v = std::inner_product(std::begin(vec), std::end(vec), std::begin(*it), 0.0);
result.push_back(v);
}Context
StackExchange Code Review Q#57052, answer score: 7
Revisions (0)
No revisions yet.