2011-11-18 3 views
8

이것이 버그인지 문서화 된 동작인지 궁금합니다.Do/Return은 컴파일에서 다르게 동작합니다 - 이유는 무엇입니까?

f1 = Function[v, 
    Do[If[v[[i]] < 0, Return[v[[i]]]], {i, 1, Length[v]}]] 

c1 = Compile[{{v, _Integer, 1}}, 
    Do[If[v[[i]] < 0, Return[v[[i]]]], {i, 1, Length[v]}]] 
부정적인 숫자를 포함하지 않는 목록에 적용 할 때, 우리는 다른 결과를 얻을

: 나는 (그것을 실제로 수정 된 버전을)를 short function를 컴파일하려고 할 때이 버그가 발생했습니다

In[66]:= Through[{f1, c1}[{1, 2, 3}]] 

Out[66]= {Null, 3} 

을 . 혼자

Do

문제 표시되지 않습니다

c2 = Compile[{}, Do[i, {i, 5}]] 

c2[] (* returns nothing, as expected *) 

답변

3

@Pillsy 및 @Leonid의 답변에서 언급했듯이 원래 함수는 종종 Null 및 정수를 반환하는 경우가 있습니다. 반대로 컴파일 된 함수는 항상 정수를 반환합니다. V8, 우리는 CompilePrint를 사용하여이를 볼 수 있습니다

 1 argument 
     1 Boolean register 
     6 Integer registers 
     1 Tensor register 
     Underflow checking off 
     Overflow checking off 
     Integer overflow checking on 
     RuntimeAttributes -> {} 

     T(I1)0 = A1 
     I3 = 0 
     I0 = 1 
     Result = I5 

1 I2 = Length[ T(I1)0] 
2 I4 = I3 
3 goto 10 
4 I5 = Part[ T(I1)0, I4] 
5 B0 = I5 < I3 
6 if[ !B0] goto 10 
7 I5 = Part[ T(I1)0, I4] 
8 goto 11 
9 goto 10 
10 if[ ++ I4 < I2] goto 4 
11 goto 12 
12 Return 

우리는 컴파일 된 함수의 결과는 것을 알 수 있습니다에서 끝나는대로 :

Needs["CompiledFunctionTools`"] 
CompilePrint @ 
    Compile[{{v,_Integer,1}},Do[If[v[[i]]<0,Return[v[[i]]]],{i,1,Length[v]}]] 

는 V8.0.4에서,이 결과를 생성하는, 정수 레지스터 I5.디 컴파일 된 명령어의 흐름에 따라 일치 항목이없는 경우 I5은 목록의 마지막 요소를 포함하게됩니다.

컴파일러의 동작은 Mathematica의 릴리스간에 변경 될 수 있습니다. 필자는 반환 결과 유형이 모호한 경우 컴파일러에서 적어도 경고를 발행해야한다고 주장하는 것이 합리적이라고 생각합니다.

+0

+1 정확히 무엇을 반환했는지 살펴 보았습니다. –

5

내가이 Compile가 작동하는 방식에 버그라고 말하고 싶지만,하지만 그것은 잘 작동하지 않는 정말 놀라운 일이 아니다. Compile은 그 입력 (여기서는 v이 정수 목록이 될 것임)뿐만 아니라 출력에 대해서도 꽤 특정한 가정을합니다. 컴파일 된 함수는 단일 특정 유형의 값을 반환해야하며 해당 유형은 컴파일 된 함수의 입력으로 사용할 수있는 유형 중 하나 여야합니다 (True|False, Integer 등). 함수가 메시지에 불만을 제기하고 Null을 반환하면 분명히 더 나을 것입니다. 그러나 컴파일을 위해 잘 작동하는 함수가되기 위해서는 적절한 정수 반환 값을 defalult로 제공해야합니다.

EDIT 출력 유형에 대한 설명은 아래 Szabolcs '에 해당합니다.

+0

입력과 동일한 유형의 값을 반환하지 않지만 특정 입력에 관계없이 동일한 유형의 값을 반환합니다 (즉, Null과 정수를 모두 반환 할 수 없음). 예, 당신이 말하는 것은 합리적입니다. – Szabolcs

4

나는 이것이 버그라고 말하지 않습니다. @Pillsy가 말한 것처럼 Compile -d 함수는 항상 동일한 유형을 반환해야하기 때문에 더 제한되어 있습니다. Do은 범위 지정 구문이므로 내의 DoDo이 아니라 Function입니다. 따라서 경우에 따라 벡터 요소를 반환하고 다른 요소에서는 Null을 반환합니다. 엄밀히 말하면, 서면으로, 함수는 전혀 컴파일해서는 안됩니다. 그러나 더 유연하고 함수 작성자가 더 잘 알고 있다고 가정하고 특정 경우에 대답을 무시합니다. 이 해석을 사용하면 Compile은 그와 같은 경우 어떠한 대답도 자유롭게 생성 할 수 있습니다. 여기서하는 일은 목록의 마지막 요소를 생성하는 것입니다. 그리고 매번 고정 된 번호를 생성하는 것보다 더 이상 특별하지 않습니다. 나는 또한 훨씬 더 유연한 기호 코드가 컴파일 될 때 이러한 모서리의 경우를 피할 수 없다고 생각한다. Compile은이 경우 더 엄격한 규칙을 적용했을 수 있으며 은 모든 경우에 의미있는 반환을 (동일한 유형의) 필요하지만이 방법이 실제로 도움이되는지는 분명하지 않습니다. 어떤면에서 C는 모두 비슷합니다. 컴파일러는 자신이하는 일을 알고 있다고 가정하지만 조심하지 않으면 많은 정의되지 않은 동작을 만들 수 있습니다.

3

유용한 추가 정보가 있습니다. 이를 고려하여 함수가 다른이 언급 한 것처럼, 따라서, = 1 마지막있어 첫 번째 요소에 반환해야 그겁니다

In[26]:= f1 = 
Function[v, Do[If[v[[i]] < 0, Return[v[[i]]]], {i, 1, Length[v]}]; 
    last = 1;]; 

In[27]:= last 

Out[27]= last 

In[28]:= f1[{-1, 2, 3}] 

In[29]:= last 

Out[29]= 1 

이 돌아 끊어집니다. 이 동작에 의존하는 코드가 너무 많아서 해결되지 않습니다.

지금, 당신의 다음을 사용할 수 있습니다 예상대로 작동

In[30]:= f2 = Function[v, Module[{}, 
    Do[If[v[[i]] < 0, Return[v[[i]], Module]], {i, 1, Length[v]}]; 
    last2 = 1;]]; 

In[31]:= f2[{-1, 2, 3}] 

Out[31]= -1 

In[32]:= last2 

Out[32]= last2 

합니다. 그러나 불행히도

In[33]:= c1 = Compile[{{v, _Integer, 1}}, 
    Module[{}, 
    Do[If[v[[i]] < 0, Return[v[[i]], Module]], {i, 1, Length[v]}]; 
    ] 
    ]; 

은 컴파일되지 않습니다.

다음은이 작업을 수행하는 방법입니다.

In[137]:= c1=Compile[{{v,_Integer,1}}, 
Module[{res=1}, 
Do[If[v[[i]]<0,res=v[[i]];Break[]],{i,1,Length[v]}]; 
If[res==1,Internal`CompileError[]]; 
res 
] 
,"RuntimeOptions"->{"RuntimeErrorHandler"->Function[Null]}] 

In[140]:= c1[{1,2,3,1}] 

In[141]:= c1[{1,2,3,-1}] 

Out[141]= -1 

출력을 확인하십시오.

In[139]:= CompilePrint[c1] 

일부 더 노트

는 "RuntimeErrorHandler"-> 기능 [널은이는 기능입니다! 한번 생각해보십시오. Thow, Message anything!

이렇게 작동합니다.

이 정보가 유용하길 바랍니다.

관련 문제