我有一个长度为11的数组double x[]
和一个函数f(double x[])
。我希望通过离散化找到函数f()
的最小值。因此,对于给定的值val1, val2, ..., valn
,我需要在{val_1,...,val_n} ^ 11中通过x的所有元组进行循环。我可以很容易地使用11个嵌套循环,但这真的是我能做的最有效吗?
修改
澄清事情:函数f()在11维集上定义。我想评估一个11维网格的顶点上的函数。对于网格大小h
,数组x[]
的条目的可能值可以是0
,h
,2*h
,...,{{1 } = val_1,val_2,...,val_n。因此,应该首先评估n*h
,然后评估f(val_1, val_1, ..., val_1)
,...和f(val_1, val_1, ...,val_1, val_2)
。我实际上并不关心顺序,但我确实关心速度,因为有很多这样的元组。确切地说,有n ^ 11个这样的元组。因此,对于n = 10,f(val_n, val_n, ..., val_n)
必须评估10 ^ 11次。我的计算机每秒可以评估f()
大约5 * 10 ^ 6次,因此对于n = 10,f()
的评估需要5个小时。这就是为什么我在寻找最有效的方法来实现它。
答案 0 :(得分:6)
这是伪代码(不一定是语法正确的C代码),用于迭代所有可能元组的非递归方法:
const int vals[] = { val1, val2, val3, ... };
int x[NUM_DIMS] = { vals[0], vals[0], ... }; // The current tuple
int i[NUM_DIMS] = { 0 }; // Index of each element in x[]
while (1)
{
f(x); // Whatever
// Update x (we increment i[] treated as a base-N number)
int j;
for (j = 0; j < NUM_DIMS; j++)
{
i[j]++; // Increment the current digit
x[j] = vals[i[j]]; // Update (via mapping)
if (i[j] < NUM_VALS) { break; } // Has this digit wrapped?
// We've caused a carry to the next digit position
i[j] = 0; // Wrap
x[j] = vals[0]; // Update (via mapping)
}
if (j == NUM_DIMS) { break; } // All digits wrapped, therefore game over
}
答案 1 :(得分:3)
当你需要的循环数太高或在编译时不知道时要做的事情是使用递归。
void check(double *x, int count) {
// Check the tuple
}
void process(double *x, double *tuple, int count, int pos) {
if (pos == count) {
check(tuple, count);
} else {
for (int i = 0 ; i != count ; i++) {
tuple[pos] = x[i];
process(x, tuple, count, pos+1);
}
}
}
int main() {
double x[11] = {1,2,3...}, tuple[11];
process(x, tuple, 11, 0);
return 0;
}
答案 2 :(得分:1)
您可能希望减轻处理器缓存的压力。因此,如果N
中的val_N
很小,并且您按照@ {OliCharlesworth建议的N
而不是N*h
来表示它,那么您可以使用较小的类型(例如unsigned char
)。
此外,循环可以简化为:
static inline int incx(uint8_t *x, unsigned int len) {
++*x;
// compute any overflow
unsigned int i = 0;
while (x[i] >= len && i < len) {
x[i++] -= len;
++x[i];
}
// if the last value overflows, we're done
return (i < len);
}
uint8_t x[LEN];
memset(x, 0, sizeof(x));
while (incx(x, sizeof(x)))
f(x);