私はいくつかの簡単な機能を持っています
int f_0(int);
int f_1(int);
...
int f_n(int);
そして、f_i() を呼び出す for ループがいくつかあります。このループの条件は同じである必要はありません。
for (int i = 0; i < n; i++) {
...
if (condition) {
int myInt = f_i(); // this is not real implementation but shows the result
// I want to achieve
... //edit
}
...
}
これを実装しようとした方法は次のとおりです。
- for ループを分解し、対応する部分で各関数を呼び出します。これにより、最速のコードが得られますが、これは非常に洗練されておらず、そのようなコードをさらに開発することは困難です。
関数へのポインタ
typedef int (*Foo) (int);
Foo fptr[] = { f_0, f_1, ... , f_n };
これは洗練された方法ですが、私の場合、ループを分割するよりも 4.4 遅くなります。関数への定数ポインターは、同様の結果をもたらします。
- 私の機能をスイッチ機能にカプセル化します。これは、ループを分割するよりも 2.6 遅くなりました。
これを実装するより良い方法はありますか?理想的な解決策はコンパクトなコードを使用するものですが、コンパイラーはループを分割し、計算を最速にします。
私は MSVC 2012 を使用しており、速度を最大化するように最適化を設定してリリース モードで実行しています。
編集:
ここに私のテストコードがあります:
head.h
namespace c {
const int w = 1024;
const int A = w * w;
}
inline int f_0(int pos) { return (pos - c::w + c::A) % c::A; }
inline int f_1(int pos) { return (pos + 1 - c::w + c::A) % c::A; }
inline int f_2(int pos) { return (pos + 1) % c::A; }
inline int f_3(int pos) { return (pos + c::w) % c::A; }
inline int f_4(int pos) { return (pos - 1 + c::w) % c::A; }
inline int f_5(int pos) { return (pos - 1 + c::A) % c::A; }
typedef int (*NEIGH_F) (int);
typedef int (* const CNEIGH_F) (int);
const NEIGH_F fptr[] = { f_0, f_1, f_2, f_3, f_4, f_5 };
const CNEIGH_F cfptr[] = { f_0, f_1, f_2, f_3, f_4, f_5 };
inline int fswitch(int i, int pos) {
switch(i) {
case 0 : return f_0(pos); break;
case 1 : return f_1(pos); break;
case 2 : return f_2(pos); break;
case 3 : return f_3(pos); break;
case 4 : return f_4(pos); break;
case 5 : return f_5(pos); break;
default : return -1; break;
}
}
main.cpp
#include "head.h"
#include <iostream>
#include <time.h>
int main()
{
int maxRepeat = 100;
clock_t startTime = clock();
double sum = 0;
for (int repeat = 0; repeat < maxRepeat; repeat++)
for (int i = 0; i < c::A; i++) {
sum += f_0(i);
sum += f_1(i);
sum += f_2(i);
sum += f_3(i);
sum += f_4(i);
sum += f_5(i);
}
std::cout << "normal time: " << (clock() - startTime)/(double)CLOCKS_PER_SEC
<< " sum is: " << sum << std::endl;
startTime = clock();
sum = 0;
for (int repeat = 0; repeat < maxRepeat; repeat++)
for (int i = 0; i < c::A; i++) {
for (int j = 0; j < 6; j++)
sum += fptr[j](i);
}
std::cout << "pointer time: " << (clock() - startTime)/(double)CLOCKS_PER_SEC
<< " sum is: " << sum << std::endl;
startTime = clock();
sum = 0;
for (int repeat = 0; repeat < maxRepeat; repeat++)
for (int i = 0; i < c::A; i++) {
for (int j = 0; j < 6; j++)
sum += cfptr[j](i);
}
std::cout << "const pointer time: " << (clock() - startTime)/(double)CLOCKS_PER_SEC
<< " sum is: " << sum << std::endl;
startTime = clock();
sum = 0;
for (int repeat = 0; repeat < maxRepeat; repeat++)
for (int i = 0; i < c::A; i++) {
for (int j = 0; j < 6; j++)
sum += fswitch(j, i);
}
std::cout << "switch time: " << (clock() - startTime)/(double)CLOCKS_PER_SEC
<< " sum is: " << sum << std::endl;
std::cin.ignore();
return 0;
}
関数 f_i は実際の実装で使用する関数ですが、実際の実装でのテスト目的のため、ここのループははるかに単純です。質問の 2 番目のコード スニペットに示されている形式の異なるループがいくつかあります。
編集2:
ループの形式は同じままである必要があります。f_i をループに入れる最良の方法を見つけたいだけです。