[완료] 연산 우선 순위에 관하여

wodnrrns의 이미지

제가 어쩌다 구현한 함수 부분 안쪽에 자꾸 조건절이 추가되게되었습니다.

if ( condition1 && condition2 || condition3 || condition4 || condition5 )

이런식입니다.
실제로 사용되는 부분은 영상쪽인데요, 영상 사이즈를 벗어나지 않고, 마스크 값이 특정 값이며
등등 조건 검사를 많이하게 됩니다.

물론 하나하나 분해해서 따로 if문을 거는것이 나머지 연산을 하지 않아도 되어 효과적일 거라는 생각은 하고 있지만
그냥 궁금한점이 있어서요.

- 질문 1: 같은 우선순위의 연산은 우측부터로 알고 있는데요. 그럼 위의 상황에서는 condition5 와 condition4 를 먼저 연산하고
다음 값들과 비교를 하는 것인가요? 왼쪽부터냐 오른쪽부터냐에따라 위의 결과가 달라질 것 같아서요.
왼쪽부터면 condition2의 값이 0이고 나머지가 모두 1이면 결과는 1이 나오지만, 오른쪽부터라면 0이 나오게 되니까요.
실험 해보면 되지만 혹시 표준이 있을까 하고 질문 드립니다.(분명히 있겠죠?)

- 질문 2: 정말 궁금한것은 이것인데요. 가령 (condition1 && condition2) || condition3 라고 하고 만약 오른쪽부터라 한다면,
condition3의 값이 1로 정해지면 이 논리식의 결과는 항상 1로 결정됩니다. 그럼 (condition1 && condition2) 를
내부적으로 계산 할까요? 최적화 옵션에따라 달라질까요? 의미상으로 condition3가 결정된다면 괄호 안쪽의 연산은
필요 없는것일것 같은데요. 이런쪽으로도 표준이 있는지 궁금합니다.

--------------------------------------------------------------------------------------------------------------------------

- 답변 1 : 우선 제가 공부를 덜해서 생긴 문제였습니다. 논리 AND와 논리 OR의 우선순위 자체가 다릅니다.
제가 가지고있던 책이 잘못나왔던 것이네요. 책한권 보고 일하느라 당연히 그런줄만 알고 다른책들 보면서도 당연한건
넘어갔던 제 불찰입니다. 그리고 연산 순서는 일반적으로 왼쪽부터가 맞습니다. 대입(=)이나 비교연산 (?:) 등 몇가지
빼고는 다 왼쪽부터 입니다.

- 답변 2 : 아래쪽에 상세하게 winner님의 답변을 보시면 될 것 같습니다.

소타의 이미지

헛; 왼쪽부터 아닌가요?;;

wodnrrns의 이미지

MSDN을 참조한 내용으로는 논리 and(&&)와 논리 or(||)의 우선순위가 다르군요.
책에서는 같다고 배운것 같은데...

표준인지는 잘 모르겠습니다.

소타의 이미지

http://msdn.microsoft.com/en-us/library/2bxt6kc4(VS.80).aspx
보시면 비교 연산은 왼쪽부터 이루어 지는게 맞네요 >_<;
순간 후덜덜 했네요. 지금까지 엄청난 버그를 양산한 줄 알고요;

wodnrrns의 이미지

Examples

The following list shows how the compiler automatically binds several sample expressions:

Expression Automatic Binding
q && r || s-- (q && r) || s––

The expression shows a correctly formed expression that may produce an unexpected result. The logical-AND operator (&&) has higher precedence than the logical-OR operator (||), so q && r is grouped as an operand. Since the logical operators guarantee evaluation of operands from left to right, q && r is evaluated before s��–. However, if q && r evaluates to a nonzero value, s–– is not evaluated, and s is not decremented. If not decrementing s would cause a problem in your program, s–– should appear as the first operand of the expression, or s should be decremented in a separate operation.

참조해주신 내용을 보니 MSDN에서 공개하고 있는 내용은 논리 AND와 논리 OR의 우선순위가 다르다고 나와있네요. 갑자기 혼란이...
어느방향 부터일까요.

winner의 이미지

|| 은 항상 왼쪽부터 조건식 전체를 판단할 수 있을 때까지 합니다.
예를 들어 true || a == 0 이면 오른쪽의 a == 0 은 연산이 이루어지지 않습니다.
이런 것을 활용해서 0 <= i && i < sz || a[i] == 0 를 하면
a 배열의 원소 수가 sz일때 i == sz 라도 오른쪽의 a[i] == 0의 연산은 이루어지지 않기 때문에
올바른 수식입니다. 이런 연산방식을 short circuit evaluation(단축평가)라고 하고요.
C, C++, Java, C# 등에서 사용하는 방식입니다.
Pascal은 모든 연산을 한다고 하더군요.

|| 뿐 아니라 && 도 마찬가지로 연산도중 false라고 판단되면 거기서 연산을 중단합니다.

C에서 &&와 ||는 초기에는 존재하지 않았는데 그당시에는 &와 |을 썼다고 하더군요.
단축평가가 항상 성능에 유리한 것은 아닙니다.
오히려 연산의 순서를 정하기 때문에 병렬처리를 막아 성능을 떨어뜨릴 수도 있죠.

wodnrrns의 이미지

short circuit evaluation 에 대해서는 KLDP 의 글들을 찾으며 보긴 했지만 제가 이해를 잘못하고 있었네요.
자세히 말씀해주신 덕분에 좋은 지식을 얻게 된것 같습니다.

지금 찾은정보로는 && 가 || 보다 우선순위가 높다고 MSDN에 나와있는데요, MSDN을 신뢰할수가 없어서
해당 내용이 표준인지 아니면 컴파일러에 따라 다른것인지 궁금하네요.

winner의 이미지

http://www.open-std.org/jtc1/sc22/wg14/www/standards

TC3까지 적용된게 공개되었군요.

jick의 이미지

하지만 우선순위가 높다는 건 "괄호를 어떻게 묶느냐"의 문제이지 연산할 때 무엇을 먼저 연산하느냐의 문제가 아닙니다.

즉 a || b && c의 경우 &&의 우선순위가 높기 때문에 a || (b && c)로 간주됩니다.

그런데 ||는 무조건 왼쪽부터 계산합니다. 왼쪽은 a, 오른쪽은 (b && c).

따라서 먼저 a를 계산하고, a가 참이면 오른쪽의 (b && c)를 연산하지 않습니다.

만약 a가 거짓이라면 마찬가지로 &&는 왼쪽부터 연산하기 때문에 먼저 b를 계산하고, b가 참일 때만 c를 계산합니다.

jick의 이미지

다시 보니,

Quote:
그리고 연산 순서는 일반적으로 왼쪽부터가 맞습니다. 대입(=)이나 비교연산 (?:) 등 몇가지
빼고는 다 왼쪽부터 입니다.

이렇게 얘기하셨는데 절대 그렇지 않습니다.

연산 순서가 왼쪽부터로 정해져 있는 것은 "&&", "||", "," (comma operator) 이 정도뿐입니다. (아마도 셋뿐인 것 같은데... 뭔가 잊어먹은 게 있을지도 모르겠습니다.)

나머지 연산은 절대로 연산 순서를 보장하지 않습니다. 예를 들어 a() + b() * c() - d()라는 수식이 있을 때 a, b, c, d 네 함수를 어느 순서로 부를 것인가는 완전히 컴파일러 마음입니다.

아무리 괄호를 많이 쳐도 전혀 소용없습니다. (물론 컴파일러 맘이기 때문에 괄호를 쳤더니 호출 순서가 바뀔 수도 있겠습니다만... 그건 순전히 우연입니다.)

"일반적으로 왼쪽부터"가 맞는 것은 연산 순서가 아니라 우선순위입니다.

즉 a + b * c의 경우 *의 우선순위가 높기 때문에 (a + b) * c가 아니라 a + (b * c)로 간주됩니다. 그러나 이 수식을 계산하기 위해 a, b, c를 먼저 어느 순서로 계산하는가 하는 것은 순전히 컴파일러 마음입니다.

wodnrrns의 이미지

제가 연산순서와 우선순위라는 말을 혼용해서 사용했던것 같네요.
개념상으로는 이해했다고 생각하면서 정리할때 잘못한것 같습니다.
jick님께서 정확히 지적해주셔서 좀 더 명확하게 기억 할 수 있을 것 같습니다.
감사합니다.

논리 연산을 할 경우 잘 신경써서 쓰면 무분별한 if 문의 중첩 없이도 효과적으로
비교문을 구성 할 수 있을 것 같습니다.
^^

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.