상세 컨텐츠

본문 제목

FAST IO 원리

카테고리 없음

by kail 2022. 4. 27. 16:03

본문

우선 fastIO란 무엇인가? 

IO 버퍼크기는 2048바이트 정도로 버퍼에서 한번에 나눠서 받기 때문에 이 값 이상의 버퍼 값이 들어온다면 비효율적으로

들어올 수 있다

따라서 우리는 이런 상황에 fastIO를 사용할 수 있다

fastIO는 값을 받을 때 한번에 받아서 해당 값을 처리해준다

코드는 아래와 같다(picuhila님의 코드를 참고하였다)

unroll-roops는 최적화에 쓰이는 방법인데, 현재에서 다루는 과정은 아니기 때문에 생략한다

#pragma GCC optimize("unroll-loops")
#include<iostream>
#include<string>
#include<vector>

using namespace std;
class FastIn
{
	public:
	const static int BUFFER_MAX = 1048575;
	static char buf[BUFFER_MAX + 1];
	static int pos;
	FastIn()
	{
		clear();
	}
	static void clear()
	{
		pos = BUFFER_MAX;
	}
	static void read_buffer()
	{
		fread(buf, sizeof(char), BUFFER_MAX, stdin);
	}
	static char getchar()
	{
		if (pos == BUFFER_MAX)
		{
			read_buffer();
			pos = 0;
		}
		return buf[pos++];
	}
	static int nextint()
	{
		int res = 0;
		char c;
		do
		{
			c = getchar();
		} while (c < '0' || c>'9');
		res = c - '0';
		while (1)
		{
			c = getchar();
			if (c < '0' || c>'9')break;
			res = (res * 10) + c - '0';
		}
			return res;
		}
	};

char FastIn::buf[FastIn::BUFFER_MAX + 1];
int FastIn::pos;
int v[3000009];
int ch[3000009];
int l, ml, mk, c,x;
int main()
{
	l = FastIn::nextint(); //총 거리
	ml = FastIn::nextint(); //기관총 유효 사거리
	mk = FastIn::nextint(); //기관총 데미지
	c = FastIn::nextint(); // 거리1에 한해 무한대 데미지를 주는 수류탄 개수
	for (int i = 0; i < l; i++)
	{
		v[i] = FastIn::nextint(); //0m부터 총거리까지 좀비체력
	}
	int dam = mk;
	for (int i = 0; i < l; i++)
	{
		if (ch[i]) dam -= mk;
		if (v[i] -dam > 0)
		{
			c--;
			if (c < 0)
			{
				cout << "NO";
				return 0;
			}
		}
		else
		{
			if (i + ml < l)
			{	
				ch[i + ml] = 1;
			}
			dam += mk;
		}
	}
	cout << "YES";
	return 0;
}

우선 fread의 코드는 아래와 같다

fread로 우리는 static으로 이미 값을 받고 해당 값을 char 배열에 넣고 시작한다
그 다음 null이라는 중간 공백으로 구분을 한다
fastio를 쓰는 예시는 아래와 같다
https://www.acmicpc.net/problem/19644
이제 여기서 나는 io값은 최대 얼마인가?
처음에는 7글자이다(3*10^6은 6글자로 표현가능 + 공백 한글자)
그 다음에는 7+(3*10^6)*4이다 (기관총 범위 3*(10^6)만큼 입력하고(총 6글자+공백 한글자), 해당 입력범위에서 각각의 거리에 대한 데미지가 최대 100까지 설정하므로 (각각 3글자+공백한글자)
그 다음에는 7글자 (3*10^6) 만큼 입력된다
그러면 왜 100만에 가까운 수부터 1mb까지가 효과적이었는가?
간단하다 입력이 최악인 경우 10^6이 아니라 10^6에 가까운 값만큼 L에 입력되었기 때문이다 그래서 1mb에 못미치는 값이 입력되었기 때문에 입력받을 떄 크기가 1mb보다 약간 작아도 잘 작동했다
이제 생기는 의문은 왜 1MB보다 큰 값에서는 오히려 시간이 오래걸리냐인데, 여기서 백준에서는 반도체 관련 기술자분들이라고 해서 이게 뭔 말이지 싶었는데
https://ljhblog.tistory.com/59
메모리 연산은 리얼모드에서 최대 1MB로 8086프로세서와 교환 가능하다
여기서 8086 프로세서가 무엇이냐하면
간단히 말하면 어셈 배울 때 Thumb Instruction이라고 해서 우리가 잘아는 명령어인 EQ(동일), GE(크거나 같다),LE(작거나 같다) 등 이거 관련 명령어를 가지고 있는 친구가(스프링 타임리프쪽에서 아마 본 적이 있을 것 같다)

https://namu.wiki/w/%EC%9D%B8%ED%85%94%208086?from=8086

8086프로세서(16비트 컴퓨터)이후에도  계속 새로운 프로세서(32비트 컴퓨터,64비트 컴퓨터)가 나왔는데

위에서 최대의 메모리를 다룰 수 있는 1MB 처리를 다루는 리얼모드는 동일한 것 같다

따라서 1MB연산이 가장 최적화되어있는 상태라고 말 할 수 있다.

아래 쪽에 관심있으면 플래그 레지스터(flag register)라고 해서 어셈에서 다루는 거라고 하니까 찾아보면 좋을 것같다