在尝试减少通过使用生成器表达式计算可能性的函数生成的分配数量时,我遇到了以下我不太理解的行为。取以下两个函数:
\nfunction testMax!(x,X,\xce\xb2)\n xmax = 0.0\n @inbounds for i \xe2\x88\x88 eachindex(x)\n x[i] = X[i,2] * \xce\xb2[1] + X[i,2] * \xce\xb2[2]\n if x[i] > xmax \n xmax = x[i]\n end \n end \n y = 0.0 \n for i \xe2\x88\x88 eachindex(x)\n y += exp(x[i]-xmax)\n end\n return xmax, y\nend\n\nfunction testMaxWeird!(x,X,\xce\xb2)\n xmax = 0.0\n @inbounds for i \xe2\x88\x88 eachindex(x)\n x[i] = X[i,2] * \xce\xb2[1] + X[i,2] * \xce\xb2[2]\n if x[i] > xmax \n xmax = x[i]\n end \n end \n y = sum(exp(x[j]-xmax) for j \xe2\x88\x88 eachindex(x))\n return xmax, y\nend\nRun Code Online (Sandbox Code Playgroud)\n两者产生相同的输出
\nusing Random\nRandom.seed!(1234)\nH = 10000;\nX = rand(H,2);\n\xce\xb2 = rand(2);\n\nx = zeros(H);\ntestMax!(x,X,\xce\xb2)\nx = zeros(H);\ntestMaxWeird!(x,X,\xce\xb2)\nRun Code Online (Sandbox Code Playgroud)\n返回(1.0772897308017204、6101.682959406999)。然而,第一个是类型稳定的,而第二个则不是(因此慢得多)。
\n@code_warntype testMax!(x,X,\xce\xb2)\n@code_warntype testMaxWeird!(x,X,\xce\xb2)\nRun Code Online (Sandbox Code Playgroud)\ny特别是,问题在于和的类型xmax,输出的差异在于@code_warntype中
y::Float64\nxmax::Float64\nRun Code Online (Sandbox Code Playgroud)\n相对
\n y::Any\n xmax@_9::Core.Box\nRun Code Online (Sandbox Code Playgroud)\n我只是很困惑为什么会发生这种情况,以及这是否是由于我定义的错误做法所致xmax在函数中多次定义的不良实践,或者是由于我使用生成器表达式的方式?
提供的参考和解决方案非常有帮助。我仍然有点困惑,不知道这到底什么时候会发生——是不是因为这样的方式xmaxfor 循环中更新的方式所致,它的范围是否与函数中定义的任何其他局部变量不同?为什么计算最大值的(效率较低)方法不会导致相同的闭包问题?
function testMax2!(x,X,\xce\xb2)\n @inbounds for i \xe2\x88\x88 eachindex(x)\n x[i] = X[i,2] * \xce\xb2[1] + X[i,2] * \xce\xb2[2]\n end \n xmax = maximum(x)\n y = sum(exp(x[j]-xmax) for j \xe2\x88\x88 eachindex(x)) \n return xmax, y\nend\nRun Code Online (Sandbox Code Playgroud)\n编辑2:没关系,我认为性能提示对此进行了解释:“解析器在将其翻译为较低级别的指令时,通过将内部函数提取到单独的代码块来实质上重新组织上述代码。” 我认为这意味着它来自多次分配的变量,因此代码的“重新排序”可能会导致混乱。
\n