array <int、SIZE> t
前述のように、C++17ではconstexprを使用できます
vector<int> countBits(int num) {
static constexpr int SIZE = 100000;
static constexpr array<int, SIZE> t {[]() constexpr {
constexpr uint32_t size = SIZE;
array<int, size> v{};
for (int i = 0; i < size; i++)
v[i] = v[i>>1] + (i & 1); // or simply v[i] = __builtin_popcount(i);
return v;}()};
vector<int> v(t.begin(), t.begin() + num + 1);
return v;
}
ただし、c++配列型を使用する必要があります。
intt[サイズ]
本当にC配列を使用したい場合は、次のトリックint [SIZE]
を使用するのとは異なります。array<int, SIZE>
グローバル配列を宣言してから、メイン内の値を計算して、コンパイル時に静的配列を作成します。
int w[100000] = {0};
vector<int> countBits(int num) {
vector<int> v(w, w + num + 1);
return v;
}
int main(void) {
for (int i = 0; i < 100000; i++)
w[i] = __builtin_popcount(i);
}
結果
実行時の出力(確かにひどい):
OK ( 591 cycles) 0,1,1, -> 0,1,1,
OK ( 453 cycles) 0,1,1,2,1,2, -> 0,1,1,2,1,2,
OK ( 455 cycles) 0,1,1,2,1,2,2,3,1,2,... -> 0,1,1,2,1,2,2,3,1,2,...
constexpr配列を使用した平均出力:
OK ( 1 cycles) 0,1,1, -> 0,1,1,
OK ( 2 cycles) 0,1,1,2,1,2, -> 0,1,1,2,1,2,
OK ( 24 cycles) 0,1,1,2,1,2,2,3,1,2,... -> 0,1,1,2,1,2,2,3,1,2,...
2番目の方法での平均出力(C ++配列のオーバーヘッドを取り除くので少し速くなります):
OK ( 0 cycles) 0,1,1, -> 0,1,1,
OK ( 1 cycles) 0,1,1,2,1,2, -> 0,1,1,2,1,2,
OK ( 23 cycles) 0,1,1,2,1,2,2,3,1,2,... -> 0,1,1,2,1,2,2,3,1,2,...
基準
私はベンチマークしました:
#include <vector>
#include <string>
#include <cstdint>
#include <array>
#include <iostream>
#include <ctime>
#include <iterator>
#include <sstream>
using namespace std;
vector<int> nums = {2, 5};
vector<vector<int>> expected = {{0,1,1}, {0,1,1,2,1,2}}; // feel free to add more tests
for (int i = 0; i < expected.size(); i++) {
clock_t start = clock();
vector<int> res = countBits(nums[i]);
double elapsedTime = (clock() - start);
printf("%s \033[30m(%4.0lf cycles)\033[0m\t %s -> %s\n", (expected[i] == res) ? "\033[34mOK" : "\033[31mKO", elapsedTime, toString(res).c_str(), toString(expected[i]).c_str());
}