C ++, 10 11 점
이것은 @Neil의 대답을 C ++로 번역 한 것으로 간단한 병렬화입니다. 2015 Macbook Pro n=9
에서 0.4 초, n=10
4.5 초, n=11
약 1 분 안에 완료됩니다 . 또한 @ChristianSievers 덕분입니다. @Neil의 답변에 대한 그의 의견으로 인해 추가 대칭이 있음을 알았습니다. n=10
반전을 고려할 때 원래 121 개의 버킷 (의 경우 )에서 66 개의 버킷으로 21 개의 버킷으로 줄었습니다.
#include <iostream>
#include <cstdint>
#include <unordered_set>
#include <thread>
#include <future>
#include <vector>
using namespace std;
constexpr uint32_t popcnt( uint32_t v ) {
uint32_t c = v - ( ( v >> 1 ) & 0x55555555 );
c = ( ( c >> 2 ) & 0x33333333 ) + ( c & 0x33333333 );
c = ( ( c >> 4 ) + c ) & 0x0F0F0F0F;
c = ( ( c >> 8 ) + c ) & 0x00FF00FF;
c = ( ( c >> 16 ) + c ) & 0x0000FFFF;
return c;
}
template<uint32_t N>
struct A {
constexpr A() : arr() {
for( auto i = 0; i != N; ++i ) {
arr[i] = popcnt( i );
}
}
uint8_t arr[N];
};
uint32_t n = ( 1 << M ) - 1;
constexpr auto a = A < 1 << M > ();
uint32_t work( uint32_t c, uint32_t g, uint32_t mult ) {
unordered_set<uint64_t> s;
// Empirically derived "optimal" value
s.reserve( static_cast<uint32_t>( pow( 5, M ) ) );
for( int i = ( 1 << M ) - 1; i >= 0; i-- ) {
for( uint32_t j = 1 << ( M - 1 ); j--; ) {
if( a.arr[i ^ j + j] != c ) {
continue;
}
for( uint32_t k = 1 << ( M - 1 ); k--; ) {
if( a.arr[i ^ k] != g ) {
continue;
}
uint64_t f = j << M | k;
uint64_t h = 0;
for( uint32_t l = M - 1; --l; ) {
h = h * ( M + 1 ) + a.arr[i ^ ( f >> l & n )];
}
s.insert( h );
}
}
}
return s.size() * mult;
}
int main() {
auto t1 = std::chrono::high_resolution_clock::now();
if( M == 1 ) {
auto t2 = std::chrono::high_resolution_clock::now();
auto seconds = chrono::duration_cast<chrono::milliseconds>( t2 - t1 ).count() / 1000.0;
cout << M << ": " << 2 << ", " << seconds << endl;
return 0;
}
uint64_t t = 0;
vector<future<uint32_t>> my_vector;
if( ( M & 1 ) == 0 ) {
for( uint32_t c = 0; c <= M / 2; ++c ) {
for( uint32_t g = c; g <= M / 2; ++g ) {
uint32_t mult = 8;
if( c == M / 2 && g == M / 2 ) {
mult = 1;
} else if( g == c || g == M / 2 ) {
mult = 4;
}
my_vector.push_back( async( work, c, g, mult ) );
}
}
for( auto && f : my_vector ) {
t += f.get();
}
} else {
for( uint32_t c = 0; c <= ( M - 1 ) / 2; ++c ) {
for( uint32_t g = c; g <= M - c; ++g ) {
uint32_t mult = 4;
if( g == c || g + c == M ) {
mult = 2;
}
my_vector.push_back( async( work, c, g, mult ) );
}
}
for( auto && f : my_vector ) {
t += f.get();
}
}
auto t2 = std::chrono::high_resolution_clock::now();
auto seconds = chrono::duration_cast<chrono::milliseconds>( t2 - t1 ).count() / 1000.0;
cout << M << ": " << t << ", " << seconds << endl;
return 0;
}
다음 스크립트를 사용하여 코드를 실행하십시오.
#!/usr/bin/env bash
for i in {1..10}
do
clang++ -std=c++14 -march=native -mtune=native -Ofast -fno-exceptions -DM=$i hamming3.cpp -o hamming
./hamming
done
출력은 다음과 같습니다. (형식은 M: result, seconds
)
1: 2, 0
2: 9, 0
3: 48, 0
4: 297, 0
5: 2040, 0
6: 15425, 0.001
7: 125232, 0.004
8: 1070553, 0.029
9: 9530752, 0.419
10: 86526701, 4.459
11: 800164636, 58.865
n=12
단일 스레드에서 계산하는 데 42 분이 걸리고 결과는 7368225813입니다.