![]() |
|
||||||||
경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지 |
|
박우성님, [optimize 때문에 그렇다]라고 그렇게 볼 문제가 아닙니다. 문제는
int n1 = int( d2 / d1 ); int n2 = int( d2 / double( 1000.0 ) ); 겉으로 보기에는 똑같아 보이는 코드를 C++ Builder는 case by case로 왜 다르게 해석하느냐가 관건이죠~ VC, gcc나 PHP는 똑같이 처리를 하는데요... 과연 fdiv대신 fmul를 써서 얻는 이득이 그렇게 클까요? 이식성이나 프로그래머가 헷갈리는 점 등등의 문제점을 덮을 정도로요? C++ Builder 측에서 보면 fmul을 쓴 것을 다른 컴파일러처럼 fdiv(물론 다른 컴파일러가 뭘쓰는 지는 모르지만 추정컨대)하는 것은 매우 쉬운 일입니다. 다만 문제가 있다면 이전 버전과의 호환성 문제가 발생할 수 있다는 겁니다. 현재 이러한 문제에 대해서 VC, gcc, PHP 등과 달리 동작하는 것처럼요. 따라서 박우성님의 원래 제기했던 문제의 핵심은 C++ Builder는 왜 다른 컴파일러와 다르게 동작하느냐는 것이었고, 그 해답이 C++ Builder가 최적화를 다르게 하기 때문에 그렇다는 것은 아니라는 거지요. 그럼 다른 컴파일러는 최적화를 안하느냐는 딜레마에 빠지게 됩니다. 지금 답을 찾으셨다고 하셨는데 원래부터 답은 [컴파일러 선택도 소비자가 했고, 컴파일러 문제점(? 원래 기능이라고 볼 수도 있겠지만요)을 발견하면 그 문제를 회피하도록 코드를 짜는 것도 소비자의 몫입니다]라는 거지요. 하지만,,, 저의 견해는 still 왜 C++ Builder는 case by case로 동작하는 코드를 만들어 내느냐 는 것입니다. int n1 = int( d2 / d1 ); int n2 = int( d2 / double( 1000.0 ) ); 는 똑같아야지요. 만약 달라도 된다고 누가 그러신다면 int n1 = int( d2 / d1 ); int n2 = int( d2 / double(double( 1000.0 )) ); 는 어떻게 동작해야 하나요? 라스코니님...
제가 "답을 찾았다"고 한 것은 C++ Builder에서 내부적으로 어떻게 처리했기에 n1과 n2의 값이 달라지는가하는 의문에 대한 답을 찾았다고 표현한 것이며, 박지훈님이 분석한 어셈블리 코드를 제가 좀더 알아보고, 처리속도를 높이기 위하여 옵티마이즈 처리를 한 것으로 본 것입니다. 옵티마이즈가 다 좋은 건 아니란 건 저도 잘 알고요. 옵티마이즈 버그 때문에, 제가 개발한 일부 모듈들은 옵티마이즈 옵션을 끄고, 컴파일 한 것도 있습니다. 제 글을 잘 보시면, 분명히 개인적인 생각은 n1과 n2의 값이 일치하는 쪽이 더 옳다는 입장입니다. Embacadero에서 이런 부분에 대하여 컴파일러 옵션에 넣어서, 기존 소스와의 호환성도 유지하고, n1과 n2의 결과값이 일치되도록 하는 옵션을 넣었으면 좋겠습니다. 하지만, 당장 Embacadero에서 이런 부분을 보완해 줄지는 미지수이기에 이 부분에 대하여 정확하게 인지하고, 주의를 기울여야 된다고 봅니다. C++ 교제에는 이런 data loss가 발생하는 형변환에서는 "결과값을 예측할 수 없다"라고 되어 있습니다. 컴파일러에 따라 그 값이 질 수 있다고 볼 수 있는데, C++ Builder만 그 결과값에 일관성이 없어서 앞으로도 계속 논란이 될 수도 있다고 봅니다. 하지만, 이번에 C++ Builder 내부 처리 방식에 대하여 많이 알게 된 것은 C++ Builder를 메인 개발툴로 사용하고 있는 저에게는 큰 도움이 되었습니다. 제가 제일 처음 제기했던 소스는 다른 컴파일러와 왜 결과값이 다른가 였지만..
http://www.borlandforum.com/impboard/impboard.dll?action=read&db=free&no=19273 더 테스트 한 후, 다시 제기한 문제는 C++ Builder의 결과값중에서 왜 n2의 결과값만 다른가였습니다. http://www.borlandforum.com/impboard/impboard.dll?action=read&db=free&no=19357 두번째 질문에 임프님이 분석을 자세히 해 주셨고, 저의 궁금증은 충분히 해소 되었습니다. 하지만, 그 처리방식에 대하여는 좋다,나쁘다 말하기는 좀 난해하지만 결과값의 일관성을 유지하는 쪽이 더 일관성이 있지 않느냐하는 것이 저의 의견입니다. 개발자가 그렇게, 즉 나눗셈에서 상수와 변수를 사용했을 때의 연산 결과가 같다고 짐작할 여지가 있다는 것은 분명하긴 합니다만.. 관점에 따라서는 부동소수점 연산에서는 있을 수 있는 문제라고 볼 수도 있다고 생각되는데요.
기본적으로 부동소수점은 두 가지 다른 방식으로 계산한 값들을 비교를 하는 것은 적절하지 않습니다. 하나의 연속된 흐름의 계산을 했을 때 최종 결과가 얼마나 정확하냐가 부동소수점 연산에서의 메인 이슈죠. 같은 맥락에서, 한 군데에서 상수로 나누었다면 다른 곳에서도 상수로 나누어야 하고 변수로 나누었다면 다른 곳에서도 변수로 나누어야 한다는 거죠. 반대로, 상수 연산에서 fdiv를 자동으로 fmul로 바꿔주는 기능은 아주 강력한 기능인데... 부동소수점 연산에서 최적화를 하려면 가장 이슈가 되는 부분들 중 하나이니까요. 박우성님 말씀처럼 fdiv보다 fmul이 압도적으로 빠르기 때문에요. 부동소수점 연산은 기본적으로 오차를 가지고 있기 때문에 오차 보정을 위한 엡실론 값을 감안해서 연산하는 게 원칙이니까, 더블 상수와 더블 변수로 나눈 값이 다르다고 하더라도 현실 세계에서 부동소수점 연산을 하는 코드에서라면 문제가 되지 않습니다. 반면 fmul 최적화로 인한 속도 증가는 엄청날 수 있기 때문에 그로 인한 이익이 훨씬 크죠. 예를 들어 CAD에서 다수의 fdiv 연산이 fmul로 효과적으로 대체되었다면 렌더링 속도가 몇 배 빨라질 수도 있죠. 이건 현실에서 소프트웨어의 가치로 보면 몇십 배 이상 차이가 날 수도 있는 문제입니다. 어차피 부동소수점 연산에서 엡실론 보정은 당연히 해야 하니까 fmul 최적화가 된 경우와 안된 경우의 결과 차이도 전혀 없을 것이고요. (만약 컴파일러가 이런 보정을 대신 해준다면 그게 쉣이죠) 다시 말하지만 부동소수점 값은 원래 오차를 감안하고 쓰는 것이고, 그게 당연한 원칙입니다. 그런 관점에서 보자면 논리적으로는 같아 보이는 두 연산의 결과가 미세하게 차이가 나는 문제보다는(그런 경우는 부동소수점 연산에서는 쎄고 쎘으니까요) 속도의 문제가 훨씬 크다고 봅니다. 전자의 이슈가 더 큰 경우라면... 제 관점에서는 꼭 상수-변수의 차이 때문이 아니더라도 부동소수점을 써서는 안되는 경우일 것 같습니다. 참고로...
아래 글은 나누기 연산에서 fdiv를 fmul로 자동으로 바꿔줄 C++ 컴파일러를 애타게 찾던 VC++ 개발자의 케이스입니다. 불행히도 C++빌더라고 대답을 해준 사람이 아무도 없었네요. (질문을 올린 당사자의 글들 외에 답변이라고 올라온 댓글들은 엄한 얘기로 삼천포로 빠져버려서 아무 도움도 안되었네요) http://forums.devshed.com/c-programming-42/do-compilers-optimize-some-into-107959.html 관련 글 리스트
|
Copyright © 1999-2015, borlandforum.com. All right reserved. |
double형과 double형을 계산하면 logn double이 되어, precisiond이 달라질 수 있다는 것과,
피연산자가 상수이거나, 변수일 때 그 생성되는 Object코드(어셈블 코드)가 달라질 수 있다는
것을 배우고 갑니다.
저도 어셈블리어를 안다면 한번 분석해 보고 싶었는데, 능력이 딸려서..
제가 찾아보니까, 일반적으로 FMUL이 FDIV보다 클러수가 적어서, 더 빠르군요.
http://en.wikipedia.org/wiki/X87
피연산자가 상수일 때, C++ Builder는 더 빠르게 처리하기 위하여, FDIV 대신 FMUL을 사용하여 옵티마이즈를 하는군요.
결국, C++ Builder의 옵티마이즈에 의한 결과값의 차이로 보이는 군요.
그래서, 예전에 똑같은 소스를 C++ Builder로 컴파일하고, VC++로 컴파일해서 속도를 테스트 해보면, C++ Builder 쪽이 더 빠른 경우가 있던데, 이번 경우처럼 C++ Builder가 옵티마이즈를 더 한다고 볼 수 있군요.
이제야 제가 원하는 답을 찾았고, 많이 배웠습니다.