> The difference in performance doesn't seem to be huge
Assuming noexcept throughout, a bitset is typically about twice as slow as an array or vector of int.
> The bitset will only need to use 32 bytes while the int array needs 1024 bytes (assuming sizeof(int) == 4).
The difference in performance is important only if the function is called a large number of times.
If it is called N times, the difference in performance is O(N)
The temporary memory used by the function is O(1) (memory for locals is immediately reclaimed when the function returns)
If the stack is too small to accommodate an object of 1K size, on intel architectures an array of bool flags (256 bytes) would give performance comparable to array of int flags.
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 96 97 98 99 100
|
#include <bitset>
#include <limits>
#include <string>
#include <vector>
#include <fstream>
#include <algorithm>
#include <random>
#include <ctime>
#include <iostream>
#include <cassert>
bool unique_chars_bitset( const std::string& str ) {
// +1: correct and not as expensive with a clever optimise
// (the optimiser can recognise that no exceptions need to be thrown)
constexpr std::size_t N = std::numeric_limits<unsigned char>::max() + 1 ;
std::bitset<N> seen ;
for( unsigned char ch : str ) {
if( seen.test(ch) ) return false;
seen.set(ch);
}
return true;
}
bool unique_chars_array_i( const std::string& str ) noexcept
{
// +1 : correct and efficient (without the +1, may engender undefined behaviour)
constexpr std::size_t N = std::numeric_limits<unsigned char>::max() + 1 ;
int seen[N] {} ;
for( unsigned char ch : str ) {
if( seen[ch] ) return false;
seen[ch] = true ;
}
return true;
}
bool unique_chars_array_b( const std::string& str ) noexcept
{
// +1 : correct and efficient (without the +1, may engender undefined behaviour)
constexpr std::size_t N = std::numeric_limits<unsigned char>::max() + 1 ;
bool seen[N] {} ;
for( unsigned char ch : str ) {
if( seen[ch] ) return false;
seen[ch] = true ;
}
return true;
}
std::vector<std::string> get_strings( std::size_t N )
{
std::string str ;
constexpr std::size_t SZ = std::numeric_limits<unsigned char>::max() ;
for( unsigned char c = 0 ; c < SZ ; ++c ) str += c ;
return { N, str } ;
}
int main()
{
std::size_t n = 0 ;
const auto seq = get_strings( 1'000'000 ) ;
clock_t bitset_ticks = 0 ;
clock_t array_ticks = 0 ;
{
const auto start = std::clock() ;
for( const std::string& str : seq ) n += unique_chars_bitset(str) ;
const auto end = std::clock() ;
std::cout << " bitset: " << ( bitset_ticks = end-start ) << " clock ticks\n" ;
}
{
const auto start = std::clock() ;
for( const std::string& str : seq ) n += unique_chars_array_i(str) ;
const auto end = std::clock() ;
std::cout << " array(int): " << ( array_ticks = end-start ) << " clock ticks\n" ;
}
{
const auto start = std::clock() ;
for( const std::string& str : seq ) n += unique_chars_array_b(str) ;
const auto end = std::clock() ;
std::cout << "array(bool): " << end-start << " clock ticks\n" ;
}
std::cout << "bitset is slower than array(int) by: " << (bitset_ticks-array_ticks)*100.0 / array_ticks << "%\n" ;
assert( n == seq.size() * 3 ) ;
return 0 ;
}
|
On X64
clang++: bitset is slower than array(int) by: 74%
g++ -O3: bitset is slower than array(int) by: 106%
Microsoft: bitset is slower than array(int) by: 129%
http://coliru.stacked-crooked.com/a/d1244a679a104753
http://rextester.com/SFWAN37914