1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
|
#include <iostream>
#include <type_traits>
#include <vector>
#include <random>
#include <ctime>
#include <map>
#include <string>
#include <iomanip>
template < typename ITERATOR > double compensated_sum( ITERATOR begin, ITERATOR end )
{
static_assert( std::is_floating_point< decltype(+*begin) >::value, "expected floating point type" ) ;
// http://en.wikipedia.org/wiki/Kahan_summation_algorithm
double sum = 0 ;
double compensation = 0 ;
for( ; begin != end ; ++begin )
{
const double term = *begin - compensation ;
const double temp = sum + term ;
compensation = ( temp - sum ) - term ;
sum = temp ;
}
return sum ;
}
std::vector<double> make_vector( std::size_t n )
{
static std::mt19937 rng( std::time(nullptr) ) ;
static std::uniform_real_distribution<double> distribution( 0, 1000 ) ;
std::vector<double> result ;
while( result.size() < n ) result.push_back( distribution(rng) ) ;
return result ;
}
int main( int argc, char* argv[] )
{
// note: will throw (and abort) on invalid command line arguments
const std::size_t nfiles = argc > 1 ? std::stoull(argv[1]) : 8 ;
const std::size_t numbers_per_file = argc > 2 ? std::stoull(argv[2]) : 4000000 ;
std::cout << nfiles << " files, " << numbers_per_file << " numbers per file\n\n" << std::fixed << std::setprecision(2) ;
{
std::cout << "one vector per file (map file name to vector):\n-------------------------\n" ;
std::map< std::string, std::vector<double> > data ;
for( std::size_t i = 0 ; i < nfiles ; ++i )
data[ "file #" + std::to_string(i) ] = make_vector(numbers_per_file) ;
const auto start = std::clock() ;
std::vector< std::pair< std::string, double> > result ;
for( const auto& pair : data ) result.emplace_back( pair.first, compensated_sum( pair.second.begin(), pair.second.end() ) ) ;
const auto end = std::clock() ;
for( const auto& pair : result ) std::cout << pair.first << ": " << pair.second << '\n' ;
std::cout << (end-start) * 1000.0 / CLOCKS_PER_SEC << " milliseconds\n\n" ;
}
{
std::cout << "a single big vector (map file name to offsets):\n-------------------------\n" ;
std::vector<double> data ;
std::map< std::string, std::pair<std::size_t,std::size_t> > offsets ;
for( std::size_t i = 0 ; i < nfiles ; ++i )
{
const auto file_data = make_vector(numbers_per_file) ;
offsets[ "file #" + std::to_string(i) ] = { data.size(), data.size() + file_data.size() } ;
data.insert( data.end(), file_data.begin(), file_data.end() ) ;
}
const auto start = std::clock() ;
std::vector< std::pair< std::string, double> > result ;
for( const auto& pair : offsets )
result.emplace_back( pair.first, compensated_sum( data.begin()+pair.second.first, data.begin()+pair.second.second ) ) ;
const auto end = std::clock() ;
for( const auto& pair : result ) std::cout << pair.first << ": " << pair.second << '\n' ;
std::cout << (end-start) * 1000.0 / CLOCKS_PER_SEC << " milliseconds\n\n" ;
}
{
std::cout << "one vector per file (vector of vectors):\n-------------------------\n" ;
std::vector< std::vector<double> > data ;
for( std::size_t i = 0 ; i < nfiles ; ++i ) data.push_back( make_vector(numbers_per_file) ) ;
const auto start = std::clock() ;
std::vector<double> result ;
for( const auto& vec : data ) result.push_back( compensated_sum( vec.begin(), vec.end() ) ) ;
const auto end = std::clock() ;
for( std::size_t i = 0 ; i < result.size() ; ++i )
std::cout << "file #" << i << ": " << result[i] << '\n' ;
std::cout << (end-start) * 1000.0 / CLOCKS_PER_SEC << " milliseconds\n\n" ;
}
}
|