float -> int 형변환시 속도가 빠르다는 이 소스 분석좀..
글쓴이: maximus / 작성시간: 수, 2004/12/01 - 1:56오후
아래는 인터넷에서 읽은 글입니다..
<<-----------------------------------------------------------------------
보통 float형을 int형으로 cast할때 (int)로 cast하는데요...
이렇게 하는 것 보다는 다음과 같이 해주면 훨씬 빠르게 됩니다.
num이란 float형 변수가 있을때
*(int *)#
라고 해주면 훨씬 빠른 프로그램을 작성할 수 있습니다.
<<------------------------------------------------------------------------
왜 그러한지 (int) 했을때와 어떻게 틀려지는지 알기 쉽게 설명좀 해주세요.
Forums:
(int)로 캐스트하면 말 그대로 캐스팅이 이루어지구요,*(int
(int)로 캐스트하면 말 그대로 캐스팅이 이루어지구요,
*(int*)&num은 float형 데이터를 int형으로 간주하고 읽으니까 반드시 올바른 값이 나올 거라고는 간주할 수 없겠는데요. 빠르기는 하겠지만요.
----------------------------
May the F/OSS be with you..
어설픈 지식으로 이런 말도 안되는 얘기를 퍼뜨리고 다니는 사람이 있다니.
어설픈 지식으로 이런 말도 안되는 얘기를 퍼뜨리고 다니는 사람이 있다니... :(
*(int*)&num 이것은 type punning이라고 하는 것인데 float형을 나타내는 비트열을
int형의 비트열로 읽겠다는 것입니다. 당연히 쓰레기값이 나옵니다.
ps. Effective C++에 나오는 우스갯소리가 생각나는군요. "나는 파블로프의 개와 비슷한
실험을 개발자들에게도 행하지 않았는가 하는 의심이 든다. 그렇지 않다면 efficiency라는
말을 들을 때마다 프로그래머들이 침을 흘리는 현상을 어떻게 설명하겠는가?"
참고
http://www-perso.iro.umontreal.ca/~feeley/cours/ift2240/doc/assembly/floatformats.html
이게 맞나봅니다.
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/_core_ieee_floating.2d.point_representation_and_microsoft_languages.asp
답변 주신분들 모두 감사합니다.MSDN 쪽 내용을 읽어 보니 대충 감
답변 주신분들 모두 감사합니다.
MSDN 쪽 내용을 읽어 보니 대충 감이 오네요..
구조적으로 메모리에서 integer 형태를 읽어와서는 값이 같다고 볼수가 없겠네요.. 덕분에 floating 저장 형태를 배울수 있었습니다...
=================================
:: how about a cup of tea ? ::
=================================
[quote="doldori"]ps. Effective C++에 나오
재미있네요~~~ :P
##########################################################
넘어지는건 아직 괜찮다.
하지만 넘어질때마다 무언가를 주워서 일어나자.
Re: float -> int 형변환시 속도가 빠르다는 이 소스 분석좀.
저 인터넷 글은 엉터리지만, 실수를 정수로 빠르게 변환하는 트릭은
있습니다. 게임 분야에 이용되는 트릭인데요... 인터넷 상에서 찾아서
제가 매크로로 정의한 것입니다. 함수 첫머리에
USE_FTOI 한 뒤,
long value = OP_FTOI(fvalue);
합니다. 이 매크로는 반올림을 자동으로 합니다.
FPU에 정수를 실수레지스터로 로드하는 인스트럭션은 있는데, 그 반대가
없습니다. 그래서 그 작업이 비교적 느린 작업에 해당합니다.
위와 같이 하면 변환 작업만 따졌을 때 꽤 많이 빨라집니다. 물론 전체
성능에 크게 영향을 미치지는 않구요.
Re: float -> int 형변환시 속도가 빠르다는 이 소스 분석좀.
로긴을 잊었군요. 위 글 제가 썼습니다.
Orion Project : http://orionids.org
Re: float -> int 형변환시 속도가 빠르다는 이 소스 분석좀.
음. 아래처럼 테스트 소스 만들어서 돌려봤습니다.(잠시 머리 식힐 겸....... 해서...)
1번은 그냥 컴파일러가 알아서 하게 했고,
2번은 올려주신 소스를 조금 고쳐서 register 키워드를 제거했습니다.
3번은 register 키워드를 다시 넣은 것이구요...
컴파일러는 gcc 3.2.3, MS Windows / MinGW / P4 2.4 GHz 입니다.
컴파일러 최적화 옵션에 따라 아래와 같은 결과가 나왔습니다.
-O0
1.... value 123456789 total 1250 ms, avg 0 ms
2.... value 123456789 total 578 ms, avg 0 ms
3.... value 123456789 total 812 ms, avg 0 ms
-O1
1.... value 123456789 total 78 ms, avg 0 ms
2.... value 123456789 total 172 ms, avg 0 ms
3.... value 123456789 total 187 ms, avg 0 ms
-O2
1.... value 123456789 total 78 ms, avg 0 ms
2.... value 123456789 total 78 ms, avg 0 ms
3.... value 123456789 total 62 ms, avg 0 ms
-O3
1.... value 123456789 total 78 ms, avg 0 ms
2.... value 123456789 total 62 ms, avg 0 ms
3.... value 123456789 total 62 ms, avg 0 ms
O2 와 O3는 거의 비슷하게 나오네요. 여러 번 실행해보면 조금씩 값이 다르게 나오는데, O2 와 O3에서는 2와 3의 결과가 바뀌는 수도 종종 있었습니다.
다른 환경에서는 어떻게 나올런지 궁금하네요.
빠른 PC나 서버 말고 좀 느린 환경에서...
Re: float -> int 형변환시 속도가 빠르다는 이 소스 분석좀.
최근 최적화 컴파일러에서 register 키워드는 별 의미가 없습니다.
대부분 알아서 잘 하니까요.
단, 지금 하신 테스트는 값을 대입하는 부분이 로컬 함수 내에서 이루어지기
때문에 속도 최적화를 한 경우, 컴파일러가 값을 한번만 변환해도 되거나,
아예 변환이 필요 없다고 판단했을 수 있습니다. 어셈블리 코드를 살펴보실
필요가 있을 것 같구요.
좀 더 정확한 테스트를 위해 변환이 항상 일어나도록 변환 부분을 함수로
빼서, 변환 결과를 포인터에 담아주거나 리턴하는 식의 코드를
반복 루프 상에서 돌려보는 게 필요할 것 같네요.
물론 고사양의 컴퓨터라 차이가 나지 않은 것일 수도 있구요.
제가 과거 486 PC 에서 테스트 해봤을 때는 정확히 기억은 안나는데,
적어도 30% 내외로 더 빨랐습니다.
Orion Project : http://orionids.org
체스맨님께서 말씀하신대로 좀 고쳐서 다시 해 봤습니다.음... 상당히
체스맨님께서 말씀하신대로 좀 고쳐서 다시 해 봤습니다.
음... 상당히 다른 결과가 나오는군요.
-O0
1.... value 123456789 total 1750 ms, avg 0 ms
2.... value 123456789 total 921 ms, avg 0 ms
3.... value 123456789 total 1579 ms, avg 0 ms
-O1
1.... value 123456789 total 1671 ms, avg 0 ms
2.... value 123456789 total 829 ms, avg 0 ms
3.... value 123456789 total 828 ms, avg 0 ms
-O2
1.... value 123456789 total 1656 ms, avg 0 ms
2.... value 123456789 total 1047 ms, avg 0 ms
3.... value 123456789 total 1031 ms, avg 0 ms
-O3
1.... value 123456789 total 62 ms, avg 0 ms
2.... value 123456789 total 203 ms, avg 0 ms
3.... value 123456789 total 188 ms, avg 0 ms
O3 무섭군요. :shock:
O2 까지는 알려주신 방법이 더 빠르게 나오고, O3에서 역전되었습니다.
레지스터 키워드를 안 쓰는게 O0에서는 확실히 더 빠르지만, O1부터는 쓰는 게 좀 더 빠르게 측정되었습니다. O1부터의 시간차는 뭐 오차범위 정도가 아닐까 싶은데요......
어셈 코드는 귀차니즘때문에 ;;
(퇴근할 시간이 지난지라...)
아 참, 그리고 올려주신 방법은 유용하게 쓸 곳이 종종 있을 듯 합니다.
감사드리구요. (처음 답글 달 때 깜빡하고 지금에서야 ...)
사용된 소스는 아래와 같습니다.
O3 결과는 의미가 없습니다.O3 는 함수 호출을 인라인화 시키는 최
O3 결과는 의미가 없습니다.
O3 는 함수 호출을 인라인화 시키는 최적화까지 합니다.
결국 빈루프를 도는 정도 시간만 측정됐을 겁니다.
그래서, 처음 하신 테스트와 결과가 비슷하죠.
게다가 OP_FTOI 가 반올림을 하기 때문에 정수 캐스트 전 반올림까지 고려하면,
양수 실수면 0.5를 음수 실수면 -0.5를 더하는 코드까지 추가되어야 합니다.
Orion Project : http://orionids.org
[code:1]#ifdef __BIGENDIAN__ # def
제가 무식해서 그런데 이코드들이 어떤 일을 해서 캐스팅이 이루어 지는지 설명좀 해주시면 많은 도움이 될 것 같습니다. 코드의 제약사항이 있으면 그것두 좀.. :oops:
제약 사항은 없습니다. 반올림이 자동으로 되는 것이 제약일 수는 있죠.
제약 사항은 없습니다. 반올림이 자동으로 되는 것이 제약일 수는 있죠.
매직값을 더한 뒤 하위 4바이트(IEEE 실수 형식상 mantissa 하위 32비트)
에서 0x80000000 을 빼는 것인데, 왜 이렇게 되는가는 IEEE 실수 형식상
그렇게 된다고 말씀드려야 할 것 같습니다.
저 값을 발견한 사람이 대단한 분이죠.
Orion Project : http://orionids.org
약간의 속도 향상과 잠재된 버그란 면에서...
IEEE 754표준인데...
암튼 최적화란 컴파일러의 목이 아닐런지...
^^
Hello World.
double -> long 만 되는게 맞는거죠? float ->
double -> long 만 되는게 맞는거죠? float -> int 안되는거죠?ㅜㅜ
당연히 float 도 됩니다. :)
당연히 float 도 됩니다. :)
Orion Project : http://orionids.org
생각해보니 제약 사항이 하나 더 있군요.IEEE 754 표준 부동
생각해보니 제약 사항이 하나 더 있군요.
IEEE 754 표준 부동 소수점 표현 형식을 사용하는 경우에만 동작합니다.
많은 S/W, H/W 들이 이 표준을 채택하기 때문에, 이것도 큰 제약은
못됩니다.
Orion Project : http://orionids.org
Re: float -> int 형변환시 속도가 빠르다는 이 소스 분석좀.
fistp 명령이면 되지 않나요?
굳이 저렇게까지...
Re: float -> int 형변환시 속도가 빠르다는 이 소스 분석좀.
제가 쓴 다음 부분을 정정합니다. windpipe 님께서 말씀해주신
fistp 명령이 있군요. 과거에 FPU 프로그래밍할 때 제가 모르고 지나쳤나봅니다.
그런데 windpipe 님 말씀처럼 fistp 를 써도 위의 변환 트릭을 두가지
측면에서 능가하지 못합니다.
첫째는 속도 측면인데요. 실재로 gcc 가 실수--> 정수 캐스팅에 그 명령을
쓰고 있습니다. -O2 옵션을 주고 어셈블리 명령을 생성해보시면 됩니다.
위에 제시된 espereto님의 테스트나 과거 제가 해봤던 테스트의 결과에서
OP_FTOI 가 C 의 캐스트 연산보다 더 빠르다는 것을 보여줍니다.
OP_FTOI 매크로를 살펴보시면, 크게 실수 덧셈과 정수 뺄셈이 쓰이는데
이것은 FPU 나 CPU 의 아주 빠른 인스트럭션들에 해당하기 때문입니다.
* 과거에 제가 사용하던 컴파일러는 최적화 옵션을 주면 캐스팅하는 부분에서
함수를 호출했었습니다. (현재 vc++ 6.0 도 이렇군요. ) 그래서 실수
정수 변환 인스트럭션이 없다고 생각했었습니다. 게다가 그 당시 제가 그것을
찾지 못했구요...
둘째는 호환성 측면입니다. fistp 는 인텔계열 FPU 에서, 어셈블리어를
사용해야만 이용할 수 있습니다. 하지만, OP_FTOI 는 IEEE 754 형식을
채택한 어떠한 플렛폼에서도 사용할 수 있습니다.
Orion Project : http://orionids.org
Re: float -> int 형변환시 속도가 빠르다는 이 소스 분석좀.
그 모든 플랫폼에서 casting보다 더 빠르다는 보장 역시 없지 않습니까? :(
인텔 호환 플랫폼으로 제한한다 하더라도 FPU가 없는 original 386에서부터 AMD64까지 수많은 x86 호환 CPU에서 어느게 더 빠르다는 말도 쉽게 하기 힘들고요.
x86계열에서는.
x86계열에서의 속도를 보자면,
와 같은 코드를 쓰는 것보다 빠르진 않을 듯합니다.
위 코드는 단 2클럭이면 해결되니까요.
Re: float -> int 형변환시 속도가 빠르다는 이 소스 분석좀.
대부분 더 빠른 것이 보장됩니다. 인스트럭션들을 분석해보시면 압니다.
혹여 앞으로 fistp 인스트럭션이 개선된다해도 OP_FTOI 와 유사한 정도에
해당할 것입니다. 특히 OP_FTOI 는 저사양 PC, PDA 등에서 좋은
성능을 보일 겁니다.
Re: float -> int 형변환시 속도가 빠르다는 이 소스 분석좀.
로그인 안해도 글 올라가는 것 너무 불편하네요.
윗 글도 제가 올렸습니다.
아...
그리고 저 연산을 매크로로 정의했던 이유는 사용하기 쉽게하기
위함도 있지만, 정수 캐스팅이 더 빠른 시스템에서는 그것으로
대체하기 쉽게하기 위한 것도 있었습니다.
말씀 드렸듯이, OP_FTOI 는 반올림이 된 결과를 내기 때문에
반올림 처리까지 고려하자면, 캐스팅은 벌써 실수 덧셈 한번이
요구됩니다. 이것이 OP_FTOI 연산에서 한번 행하는 실수 덧셈과
대응한다고 보면, 결국 정수 뺄셈 속도만큼 실수->정수 변환
인스트럭션이 빨라져야 한다는 것을 의미합니다.
그래서 대부분 OP_FTOI 가 더 빠를 것으로 예상할 수 있습니다.
Orion Project : http://orionids.org
저거 사용할
저거 사용할때 주의점은
float 에서는 값이 2^23 보다 크면 변환이 제대로 안됩니다.
double에서는 2^52보다 크면 제대로 변환이 안됩니다.,
정말 대단.. ㅡㅜ
제가 필요로 하던 정보 였습니다.
감사 합니다.
댓글 달기