float -> int 형변환시 속도가 빠르다는 이 소스 분석좀..

maximus의 이미지

아래는 인터넷에서 읽은 글입니다..

<<-----------------------------------------------------------------------
보통 float형을 int형으로 cast할때 (int)로 cast하는데요...
이렇게 하는 것 보다는 다음과 같이 해주면 훨씬 빠르게 됩니다.
num이란 float형 변수가 있을때

*(int *)&num;

라고 해주면 훨씬 빠른 프로그램을 작성할 수 있습니다.
<<------------------------------------------------------------------------

왜 그러한지 (int) 했을때와 어떻게 틀려지는지 알기 쉽게 설명좀 해주세요.

hey의 이미지

(int)로 캐스트하면 말 그대로 캐스팅이 이루어지구요,

*(int*)&num은 float형 데이터를 int형으로 간주하고 읽으니까 반드시 올바른 값이 나올 거라고는 간주할 수 없겠는데요. 빠르기는 하겠지만요.


----------------------------
May the F/OSS be with you..


doldori의 이미지

어설픈 지식으로 이런 말도 안되는 얘기를 퍼뜨리고 다니는 사람이 있다니... :(
*(int*)&num 이것은 type punning이라고 하는 것인데 float형을 나타내는 비트열을
int형의 비트열로 읽겠다는 것입니다. 당연히 쓰레기값이 나옵니다.

ps. Effective C++에 나오는 우스갯소리가 생각나는군요. "나는 파블로프의 개와 비슷한
실험을 개발자들에게도 행하지 않았는가 하는 의심이 든다. 그렇지 않다면 efficiency라는
말을 들을 때마다 프로그래머들이 침을 흘리는 현상을 어떻게 설명하겠는가?"

익명 사용자의 이미지

maximus의 이미지

답변 주신분들 모두 감사합니다.
MSDN 쪽 내용을 읽어 보니 대충 감이 오네요..

구조적으로 메모리에서 integer 형태를 읽어와서는 값이 같다고 볼수가 없겠네요.. 덕분에 floating 저장 형태를 배울수 있었습니다...

=================================
:: how about a cup of tea ? ::
=================================

zienie의 이미지

doldori wrote:

ps. Effective C++에 나오는 우스갯소리가 생각나는군요. "나는 파블로프의 개와 비슷한
실험을 개발자들에게도 행하지 않았는가 하는 의심이 든다. 그렇지 않다면 efficiency라는
말을 들을 때마다 프로그래머들이 침을 흘리는 현상을 어떻게 설명하겠는가?"

재미있네요~~~ :P

##########################################################
넘어지는건 아직 괜찮다.
하지만 넘어질때마다 무언가를 주워서 일어나자.

익명 사용자의 이미지

저 인터넷 글은 엉터리지만, 실수를 정수로 빠르게 변환하는 트릭은
있습니다. 게임 분야에 이용되는 트릭인데요... 인터넷 상에서 찾아서
제가 매크로로 정의한 것입니다. 함수 첫머리에
USE_FTOI 한 뒤,
long value = OP_FTOI(fvalue);
합니다. 이 매크로는 반올림을 자동으로 합니다.

#ifdef __BIGENDIAN__
#	define FTOI_LONG reserved, l
#else
#	define FTOI_LONG l
#endif
#define USE_FTOI register union{ double r; struct { _integer4 FTOI_LONG; } l; } __ftoitmp;
#define OP_FTOI(val)\
 ( ( (__ftoitmp.r=(val)+((((65536.*65536.*16.)+(65536.*.5))*65536.)) ),\
     __ftoitmp.l.l-0x80000000L ) )

FPU에 정수를 실수레지스터로 로드하는 인스트럭션은 있는데, 그 반대가
없습니다. 그래서 그 작업이 비교적 느린 작업에 해당합니다.

위와 같이 하면 변환 작업만 따졌을 때 꽤 많이 빨라집니다. 물론 전체
성능에 크게 영향을 미치지는 않구요.

체스맨의 이미지

로긴을 잊었군요. 위 글 제가 썼습니다.

Orion Project : http://orionids.org

espereto의 이미지

Anonymous wrote:
저 인터넷 글은 엉터리지만, 실수를 정수로 빠르게 변환하는 트릭은
있습니다. 게임 분야에 이용되는 트릭인데요... 인터넷 상에서 찾아서
제가 매크로로 정의한 것입니다. 함수 첫머리에
USE_FTOI 한 뒤,
long value = OP_FTOI(fvalue);
합니다. 이 매크로는 반올림을 자동으로 합니다.

#ifdef __BIGENDIAN__
#	define FTOI_LONG reserved, l
#else
#	define FTOI_LONG l
#endif
#define USE_FTOI register union{ double r; struct { _integer4 FTOI_LONG; } l; } __ftoitmp;
#define OP_FTOI(val)\
 ( ( (__ftoitmp.r=(val)+((((65536.*65536.*16.)+(65536.*.5))*65536.)) ),\
     __ftoitmp.l.l-0x80000000L ) )

FPU에 정수를 실수레지스터로 로드하는 인스트럭션은 있는데, 그 반대가
없습니다. 그래서 그 작업이 비교적 느린 작업에 해당합니다.

위와 같이 하면 변환 작업만 따졌을 때 꽤 많이 빨라집니다. 물론 전체
성능에 크게 영향을 미치지는 않구요.

음. 아래처럼 테스트 소스 만들어서 돌려봤습니다.(잠시 머리 식힐 겸....... 해서...)

#include <stdio.h>
#include <stdlib.h>

#ifndef _WIN32
/* for linux/unix */
#include <time.h>
#include <sys/time.h>
static void printf_localtime()
{
	struct tm * ttt;
	struct timeval tv;
	gettimeofday(&tv, NULL);
	ttt = localtime(&tv);

	printf("%.4d-%.2d-%.2d  %.2d:%.2d:%.2d.%.3d", ttt->tm_year, ttt->tm_mon, ttt->tm_mday, ttt->tm_hour, ttt->tm_min, ttt->tm_sec, tv.tv_usec/1000);
}

static unsigned int get_clock()
{
        struct timeval tv;
        unsigned int t;

        gettimeofday(&tv, NULL);

        t = ((tv.tv_sec % 1000000) * 1000) + (tv.tv_usec / 1000);

        return t;
}

#else
/* for windows */
#define get_clock	clock
#endif

#ifdef __BIGENDIAN__ 
#   define FTOI_LONG reserved, l 
#else 
#   define FTOI_LONG l 
#endif 
#define USE_FTOI union{ double r; struct { long FTOI_LONG; } l; } __ftoitmp; 
#define OP_FTOI(val) \
 ( ( (__ftoitmp.r=(val)+((((65536.*65536.*16.)+(65536.*.5))*65536.)) ), \
     __ftoitmp.l.l-0x80000000L ) ) 

#define USE_FTOI2 union{ double r; struct { long FTOI_LONG; } l; } __ftoitmp; 

#define LOOPCNT1	10
#define LOOPCNT2	10000000
void test1()
{
	double dval = 123456789.12345678;
	long lval = 0;
	long total = 0;
	long start = 0, finish = 0;
	long avg = 0;
	long i=0, j=0;

	start = get_clock();
	for(j=0; j<LOOPCNT1; j++) {
		for(i=0; i<LOOPCNT2; i++) {
			lval = dval;
		}
	}
	finish = get_clock();
	total = finish - start;
	avg = total / LOOPCNT1 / LOOPCNT2;

	printf("1.... value %ld total %ld ms, avg %ld ms\n", lval, total, avg);
}

void test2()
{
	USE_FTOI
	double dval = 123456789.12345678;
	long lval = 0;
	long total = 0;
	long start = 0, finish = 0;
	long avg = 0;
	long i=0, j=0;

	start = get_clock();
	for(j=0; j<LOOPCNT1; j++) {
		for(i=0; i<LOOPCNT2; i++) {
			lval = OP_FTOI(dval);
		}
	}
	finish = get_clock();
	total = finish - start;
	avg = total / LOOPCNT1 / LOOPCNT2;

	printf("2.... value %ld total %ld ms, avg %ld ms\n", lval, total, avg);
}

void test3()
{
	register USE_FTOI
	double dval = 123456789.12345678;
	long lval = 0;
	long total = 0;
	long start = 0, finish = 0;
	long avg = 0;
	long i=0, j=0;

	start = get_clock();
	for(j=0; j<LOOPCNT1; j++) {
		for(i=0; i<LOOPCNT2; i++) {
			lval = OP_FTOI(dval);
		}
	}
	finish = get_clock();
	total = finish - start;
	avg = total / LOOPCNT1 / LOOPCNT2;

	printf("3.... value %ld total %ld ms, avg %ld ms\n", lval, total, avg);
}

int main(int argc, char *argv[])
{
	test1();
	test2();
	test3();

	return 0;
}

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나 서버 말고 좀 느린 환경에서...

체스맨의 이미지

최근 최적화 컴파일러에서 register 키워드는 별 의미가 없습니다.
대부분 알아서 잘 하니까요.

단, 지금 하신 테스트는 값을 대입하는 부분이 로컬 함수 내에서 이루어지기
때문에 속도 최적화를 한 경우, 컴파일러가 값을 한번만 변환해도 되거나,
아예 변환이 필요 없다고 판단했을 수 있습니다. 어셈블리 코드를 살펴보실
필요가 있을 것 같구요.

좀 더 정확한 테스트를 위해 변환이 항상 일어나도록 변환 부분을 함수로
빼서, 변환 결과를 포인터에 담아주거나 리턴하는 식의 코드를
반복 루프 상에서 돌려보는 게 필요할 것 같네요.

물론 고사양의 컴퓨터라 차이가 나지 않은 것일 수도 있구요.
제가 과거 486 PC 에서 테스트 해봤을 때는 정확히 기억은 안나는데,
적어도 30% 내외로 더 빨랐습니다.

Orion Project : http://orionids.org

espereto의 이미지

체스맨님께서 말씀하신대로 좀 고쳐서 다시 해 봤습니다.
음... 상당히 다른 결과가 나오는군요.

-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부터의 시간차는 뭐 오차범위 정도가 아닐까 싶은데요......

어셈 코드는 귀차니즘때문에 ;;
(퇴근할 시간이 지난지라...)

아 참, 그리고 올려주신 방법은 유용하게 쓸 곳이 종종 있을 듯 합니다.
감사드리구요. (처음 답글 달 때 깜빡하고 지금에서야 ...)

사용된 소스는 아래와 같습니다.

#include <stdio.h>
#include <stdlib.h>

#ifndef _WIN32
/* for linux/unix */
#include <time.h>
#include <sys/time.h>
static void printf_localtime()
{
	struct tm * ttt;
	struct timeval tv;
	gettimeofday(&tv, NULL);
	ttt = localtime(&tv);

	printf("%.4d-%.2d-%.2d  %.2d:%.2d:%.2d.%.3d", ttt->tm_year, ttt->tm_mon, ttt->tm_mday, ttt->tm_hour, ttt->tm_min, ttt->tm_sec, tv.tv_usec/1000);
}

static unsigned int get_clock()
{
        struct timeval tv;
        unsigned int t;

        gettimeofday(&tv, NULL);

        t = ((tv.tv_sec % 1000000) * 1000) + (tv.tv_usec / 1000);

        return t;
}

#else
/* for windows */
#define get_clock	clock
#endif

#ifdef __BIGENDIAN__ 
#   define FTOI_LONG reserved, l 
#else 
#   define FTOI_LONG l 
#endif 
#define USE_FTOI union{ double r; struct { long FTOI_LONG; } l; } __ftoitmp; 
#define OP_FTOI(val) \
 ( ( (__ftoitmp.r=(val)+((((65536.*65536.*16.)+(65536.*.5))*65536.)) ), \
     __ftoitmp.l.l-0x80000000L ) ) 

#define USE_FTOI2 union{ double r; struct { long FTOI_LONG; } l; } __ftoitmp; 

#define LOOPCNT1	10
#define LOOPCNT2	10000000

void conv1(double *dv, long *lv)
{
	*lv = *dv;
}

void test1()
{
	double dval = 123456789.12345678;
	long lval = 0;
	long total = 0;
	long start = 0, finish = 0;
	long avg = 0;
	long i=0, j=0;

	start = get_clock();
	for(j=0; j<LOOPCNT1; j++) {
		for(i=0; i<LOOPCNT2; i++) {
			conv1(&dval, &lval);
		}
	}
	finish = get_clock();
	total = finish - start;
	avg = total / LOOPCNT1 / LOOPCNT2;

	printf("1.... value %ld total %ld ms, avg %ld ms\n", lval, total, avg);
}

void conv2(double *dv, long *lv)
{
	USE_FTOI
	*lv = OP_FTOI(*dv);
}

void test2()
{
	double dval = 123456789.12345678;
	long lval = 0;
	long total = 0;
	long start = 0, finish = 0;
	long avg = 0;
	long i=0, j=0;

	start = get_clock();
	for(j=0; j<LOOPCNT1; j++) {
		for(i=0; i<LOOPCNT2; i++) {
			conv2(&dval, &lval);
		}
	}
	finish = get_clock();
	total = finish - start;
	avg = total / LOOPCNT1 / LOOPCNT2;

	printf("2.... value %ld total %ld ms, avg %ld ms\n", lval, total, avg);
}

void conv3(double *dv, long *lv)
{
	register USE_FTOI
	*lv = OP_FTOI(*dv);
}

void test3()
{
	double dval = 123456789.12345678;
	long lval = 0;
	long total = 0;
	long start = 0, finish = 0;
	long avg = 0;
	long i=0, j=0;

	start = get_clock();
	for(j=0; j<LOOPCNT1; j++) {
		for(i=0; i<LOOPCNT2; i++) {
			conv3(&dval, &lval);
		}
	}
	finish = get_clock();
	total = finish - start;
	avg = total / LOOPCNT1 / LOOPCNT2;

	printf("3.... value %ld total %ld ms, avg %ld ms\n", lval, total, avg);
}

int main(int argc, char *argv[])
{
	test1();
	test2();
	test3();

	return 0;
}

체스맨의 이미지

O3 결과는 의미가 없습니다.
O3 는 함수 호출을 인라인화 시키는 최적화까지 합니다.
결국 빈루프를 도는 정도 시간만 측정됐을 겁니다.
그래서, 처음 하신 테스트와 결과가 비슷하죠.

게다가 OP_FTOI 가 반올림을 하기 때문에 정수 캐스트 전 반올림까지 고려하면,
양수 실수면 0.5를 음수 실수면 -0.5를 더하는 코드까지 추가되어야 합니다.

Orion Project : http://orionids.org

익명 사용자의 이미지

#ifdef __BIGENDIAN__ 
#   define FTOI_LONG reserved, l 
#else 
#   define FTOI_LONG l 
#endif 
#define USE_FTOI register union{ double r; struct { _integer4 FTOI_LONG; } l; } __ftoitmp; 
#define OP_FTOI(val)\ 
 ( ( (__ftoitmp.r=(val)+((((65536.*65536.*16.)+(65536.*.5))*65536.)) ),\ 
     __ftoitmp.l.l-0x80000000L ) ) 

제가 무식해서 그런데 이코드들이 어떤 일을 해서 캐스팅이 이루어 지는지 설명좀 해주시면 많은 도움이 될 것 같습니다. 코드의 제약사항이 있으면 그것두 좀.. :oops:

체스맨의 이미지

제약 사항은 없습니다. 반올림이 자동으로 되는 것이 제약일 수는 있죠.
매직값을 더한 뒤 하위 4바이트(IEEE 실수 형식상 mantissa 하위 32비트)
에서 0x80000000 을 빼는 것인데, 왜 이렇게 되는가는 IEEE 실수 형식상
그렇게 된다고 말씀드려야 할 것 같습니다.

저 값을 발견한 사람이 대단한 분이죠.

Orion Project : http://orionids.org

오호라의 이미지

IEEE 754표준인데...

암튼 최적화란 컴파일러의 목이 아닐런지...

^^

Hello World.

익명 사용자의 이미지

double -> long 만 되는게 맞는거죠? float -> int 안되는거죠?ㅜㅜ

체스맨의 이미지

당연히 float 도 됩니다. :)

Orion Project : http://orionids.org

체스맨의 이미지

생각해보니 제약 사항이 하나 더 있군요.

IEEE 754 표준 부동 소수점 표현 형식을 사용하는 경우에만 동작합니다.
많은 S/W, H/W 들이 이 표준을 채택하기 때문에, 이것도 큰 제약은
못됩니다.

Orion Project : http://orionids.org

windpipe의 이미지

Anonymous wrote:
저 인터넷 글은 엉터리지만, 실수를 정수로 빠르게 변환하는 트릭은
있습니다. 게임 분야에 이용되는 트릭인데요... 인터넷 상에서 찾아서
제가 매크로로 정의한 것입니다. 함수 첫머리에
USE_FTOI 한 뒤,
long value = OP_FTOI(fvalue);
합니다. 이 매크로는 반올림을 자동으로 합니다.

#ifdef __BIGENDIAN__
#	define FTOI_LONG reserved, l
#else
#	define FTOI_LONG l
#endif
#define USE_FTOI register union{ double r; struct { _integer4 FTOI_LONG; } l; } __ftoitmp;
#define OP_FTOI(val)\
 ( ( (__ftoitmp.r=(val)+((((65536.*65536.*16.)+(65536.*.5))*65536.)) ),\
     __ftoitmp.l.l-0x80000000L ) )

FPU에 정수를 실수레지스터로 로드하는 인스트럭션은 있는데, 그 반대가
없습니다. 그래서 그 작업이 비교적 느린 작업에 해당합니다.

위와 같이 하면 변환 작업만 따졌을 때 꽤 많이 빨라집니다. 물론 전체
성능에 크게 영향을 미치지는 않구요.

fistp 명령이면 되지 않나요?
굳이 저렇게까지...

체스맨의 이미지

제가 쓴 다음 부분을 정정합니다. windpipe 님께서 말씀해주신
fistp 명령이 있군요. 과거에 FPU 프로그래밍할 때 제가 모르고 지나쳤나봅니다.

체스맨 wrote:

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

cdpark의 이미지

체스맨 wrote:

둘째는 호환성 측면입니다. fistp 는 인텔계열 FPU 에서, 어셈블리어를
사용해야만 이용할 수 있습니다. 하지만, OP_FTOI 는 IEEE 754 형식을
채택한 어떠한 플렛폼에서도 사용할 수 있습니다.

그 모든 플랫폼에서 casting보다 더 빠르다는 보장 역시 없지 않습니까? :(

인텔 호환 플랫폼으로 제한한다 하더라도 FPU가 없는 original 386에서부터 AMD64까지 수많은 x86 호환 CPU에서 어느게 더 빠르다는 말도 쉽게 하기 힘들고요.

windpipe의 이미지

x86계열에서의 속도를 보자면,

fprep   dd      59c00000h       

        fadd    [fprep]         
        fsub    [fprep]   

와 같은 코드를 쓰는 것보다 빠르진 않을 듯합니다.
위 코드는 단 2클럭이면 해결되니까요.
익명 사용자의 이미지

cdpark wrote:

그 모든 플랫폼에서 casting보다 더 빠르다는 보장 역시 없지 않습니까? :(

대부분 더 빠른 것이 보장됩니다. 인스트럭션들을 분석해보시면 압니다.

혹여 앞으로 fistp 인스트럭션이 개선된다해도 OP_FTOI 와 유사한 정도에
해당할 것입니다. 특히 OP_FTOI 는 저사양 PC, PDA 등에서 좋은
성능을 보일 겁니다.

체스맨의 이미지

로그인 안해도 글 올라가는 것 너무 불편하네요.
윗 글도 제가 올렸습니다.

아...
그리고 저 연산을 매크로로 정의했던 이유는 사용하기 쉽게하기
위함도 있지만, 정수 캐스팅이 더 빠른 시스템에서는 그것으로
대체하기 쉽게하기 위한 것도 있었습니다.

말씀 드렸듯이, OP_FTOI 는 반올림이 된 결과를 내기 때문에
반올림 처리까지 고려하자면, 캐스팅은 벌써 실수 덧셈 한번이
요구됩니다. 이것이 OP_FTOI 연산에서 한번 행하는 실수 덧셈과
대응한다고 보면, 결국 정수 뺄셈 속도만큼 실수->정수 변환
인스트럭션이 빨라져야 한다는 것을 의미합니다.

그래서 대부분 OP_FTOI 가 더 빠를 것으로 예상할 수 있습니다.

Orion Project : http://orionids.org

kkb110의 이미지

저거 사용할때 주의점은

float 에서는 값이 2^23 보다 크면 변환이 제대로 안됩니다.
double에서는 2^52보다 크면 제대로 변환이 안됩니다.,

익명 사용자의 이미지

제가 필요로 하던 정보 였습니다.
감사 합니다.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.