我正在研究Numerical Recipes的 Nelder-Mead 算法的变体,它允许用户指定要进行的目标函数调用的最大数量。
在我的主例程中,我如何调用实现 Nelder-Mead 算法的
amoeba()
函数:
amoeba(p,y,params->ndim,params->tol,params->nmax,internal_funk,&nfunc);
但它是如何实现的:
void amoeba(float **p, float y[], int ndim, unsigned nmax, float ftol, float (*funk)(float []), int *nfunk) {
....
}
请注意,我在函数调用中颠倒了
nmax
和 ftol
参数。
令人惊讶的是,
amoeba()
仍然有效。在调试器中单步调试,确认已为 nmax
和 ftol
分配了正确的值。
我的主例程
#include
定义了amoeba()
例程的签名的头文件,并且编译主例程没有产生错误。但是,amoeaba()
源文件不包含该标头(我的错误),因此编译器也没有生成任何错误。
那么,即使参数没有按正确的顺序给出,为什么我的链接程序仍然可以正常运行?
更新
@Binyamin Sharet,我在这里展示了调用
amoeba
之前和 amoeba
中的程序集。它支持你的假设吗?
原因可能是,因为浮点参数不是在堆栈上传递的,而是在协处理器堆栈上传递的,所以这两个参数的顺序并不重要。
例如,函数需要以下参数顺序:
| p | |
| y | |
| ndim | |
| nmax | |
| funk | |
| nfunk | ftol |
+------------------------+-----------------------------+
| stack | coprocessor stack |
如果你切换
nmax
和 ftol
也没关系,因为堆栈上的顺序是相同的,并且当 amoeba
尝试读取它们时,它不会因为同样的原因而感到困惑。
编辑
阅读反汇编表明我有点偏离,但由于SSE,用于传递浮点变量的指令是
movss
,您可以在添加的两个汇编列表中看到它,一次到 xmm0
注册(在调用者中),并从 xmm0
(在被调用者中)注册一次。所以你可以用 xmm 寄存器 替换单词 coprocessor-stack 这就是你的情况。