프로그래밍 언어론 6-1-4강. 표현식 내의 순서(Ordering within Expressions)

[프로그래밍 언어론]

2019. 11. 18. 14:20

 

[표현식 내의 순서]

: 우선 순위 및 연관성 규칙들은 표현식 내에서 이진 중위 연산자를 적용하는 순서를 정의하는 반면, 주어진 연산자의 피연산자가 평가되는 순서를 지정하지 않는다.

ex) a - f(b) - c * d

ex) f(a, g(b), h(c))       //마찬가지로 계산순서 문제

: 각 표현식들에 대한 결과 값을 뽑아내야 계산할수 있다.

: 그리고 계산 순서는 c, d, a, f(b) 순서가 될꺼라고 예측되는데, 만약 f(b)에서 side effect로 a, c, d의 변수들을 수정한다면?

=> 어떤 것을 먼저 호출하느냐에 따라 값이 변한다.

 

 

 

[계산 순서가 중요한 이유]

1. Side effect

  : 앞에서 말한것과 같이, 늦게 호출된 표현식에서 앞서 계산한 표현식을 수정하는 side effect가 일어날수 있다.

2. Code improvement

  : 최적화 작업. 부분표현식들의 계산 순서는 레지스터 할당과 스케줄링에 영향을 준다.

  : 이런 최적화 작업의 중요성때문에 대부분의 언어에서 계산순서를 정의 하지 않는다 (side effect측면에선 반대로 정의 권장)

  : 이러한 정해진 계산 순서가 없으면, 컴파일러는 더빠른 방법으로 결과를 추출한다.

  +) Java, C# : 계산순서 left-to-right 로 정의한다(특별)

 

 

 

[Code imporvement 예시]

# Code importvement 예시 1

a * b + f(c)

: a * b 연산을 하기 전에 함수 f를 호출한다.

: 먼저 a*b를 계산하면, 이후 함수 f를 호출하는 동안, 앞의 계산값이 계속 reg를 차지하고 있게된다.

 

# Code importvement 예시 2

a := B[i];

c := a * 2 + d * 3;

: 프로세서에서, 먼저 d * 3을 계산하고, a * 2를 계산할 것이다.

: 왜냐하면 앞의 a:= B[i]는 메모리에서부터 로딩해야하며 이는 느리기 때문에, 플세서는 빨리 계산가능한 뒤의 연산부터 계산한다.

 

 

 

[수학적 식별자 적용(Applying Mathematical Identities)]

: 몇몇 언어들은 컴파일러가 수학적 추상들이 가환적이고, 연관적이고, 분배적인 표현식들을 더빠른 순서로 재배열하는 것을 허용한다.

 

# 수학적 연관 표현식 재배열 예시(Fortran)

a = b + c

d = c + e + b

=>

a = b + c

d = b + c + e

=>

a = b + c

d = a + e

a = b / c / d

e = f / d / c

=>

t = c * d

a = b / t

e = f / t

: 하지만 컴퓨터의 숫자의 크기에 한계가 존재하기에 제약이 존재한다.

ex) a / c * b 였는데, a * b / c 로 순서 바꿨지만, a * b의 결과가 컴퓨터 숫자 한계 overflow발생할때

 

 

 

[언어별 재배열시 overflow 발생 문제 해결법]

1. Pascal 계통 언어 : rearrange 할때 문제 발생 체크하는 체크 코드 추가 삽입 => 하지만 속도 감소(overhead)

2. C, C++ : overflow 확인 안하고 사용자에게 맡긴다

3. Java : 모든 타입의 바이트 크기, overfow를 잘 정의해놓았다.

4. C# : overflow 체크 유무 선택 가능하다.

5. Scheme, Lisp, 여러 스크립트 언어 : 요구되는 만큼의 숫자 표기 공간을 할당해 정수의 크기 제한이 없다.

# 이러한 overflow문제 말고도, 소수점 표현(불명확한 표기법)에서도 같은 이유로 문제가 발생할 수 있다.