정상성

시계열 데이터의 통계적 속성이 시간에 따라 변하지 않음을 의미하는데, 데이터의 평균과 분산이 일정함을 의미한다.

 

adfuller() 함수를 통해 시계열 데이터의 정상성을 검증하기 위한 Augmented Dicker-Fuller 테스트를 수행한다.

from statsmodels.tsa.stattools import adfuller

# ADF 테스트
adf_result = adfuller(train_data['평균기온'])
print(f'ADF 통계값: {adf_result[0]}')
print(f'p-value: {adf_result[1]}')

 

ADF 테스트

ADF 테스트는 '단위근'이라는 특정 유형의 비정상성을 확인한다.

 

이 테스트에서 계산되는 ADF 통계치는 데이터에 단위근이 없다는 대립 가설에 대한 증거를 제공한다.

 

p - value는 이 통계치가 얼마나 유의미한지를 나타낸다. 

일반적으로 p-value가 0.05 이하일 경우, 우리는 데이터가 정상성을 가지고 있다고 간주하고 귀무 가설을 기각할 수 있다.

 

 

예를 들어

만약 코드 실행 결과, ADF 통계값은 -2.904, p-value는 0.044로 나타났을 경우, 일반적으로 p-value가 0.05 이하일 경우에는 귀무가설을 기각하고 데이터가 정상성을 가진다고 할 수 있지만...

이 경우에는 p-value가 0.05에 근접하여 데이터가 정상 시계열이라고 결론짓기에는 약간의 불확실성이 남는다.

 

따라서 이 경우, 차분을 수행하여 정상성을 확인하거나 모델의 성능을 검증하여 평가할 수 있다. 

 

혹은 p와 q의 범위 내에서 여러 ARIMA 모델을 피팅하고 각 모델의 AIC(Akaike Information Criterion) 값을 비교함으로써 최적의 파라미터 조합을 찾는 방법을 사용할 수도 있다.

 

AIC는 모델의 적합도와 복잡도를 동시에 고려하는 척도로, 낮은 AIC 값을 가지는 모델이 주어진 데이터에 대해 더 좋은 예측 성능을 제공할 가능성이 높다. 

'프로그래밍 > 프로젝트' 카테고리의 다른 글

쇼핑몰 지점별 매출 예측 AI  (0) 2024.08.29
자기상관분석  (0) 2024.05.21
ARIMA 모델 검증 및 예측 정확도 평가  (0) 2024.05.21
ARIMA 모델  (0) 2024.05.21
데이콘 - 고객 대출 등급 분류 프로젝트  (1) 2024.02.09

평균 절대 오차 (Mean Absolute Error, MAE)

 

MAE는 회귀 문제에서 모델의 정확도를 평가하는데 사용되는 방법 중 하나이다.

 

MAE는 실제값과 예측값 간의 차이의 절대값의 평균을 의미한다. 

이는 모델의 예측이 얼마나 정확한지를 나타내는 지표로, 값이 낮을수록 더 정확한 예측을 의미한다. 

 

장점

  • 모든 오차의 절대값을 평균을 계산하므로, 예측하고자 하는 단위가 동일하다. (예: MAE가 5라면 모델이 평균적으로 실제값과 5정도 차이남을 나타낸다.)
  • 다른 평가 지표에 비해 이상치에 덜 민감하다.

 

단점

  • 모든 오차를 동일하게 취급하므로, 특정 오차에 가중치를 주고싶을 경우 부적절한 평가방법일 수 있다.

 

'프로그래밍 > 프로젝트' 카테고리의 다른 글

자기상관분석  (0) 2024.05.21
시계열 데이터의 정상성  (0) 2024.05.21
ARIMA 모델  (0) 2024.05.21
데이콘 - 고객 대출 등급 분류 프로젝트  (1) 2024.02.09
고객 유지를 위한 필요한 행동 예측  (1) 2024.01.14

ARIMA 

- 자기회귀 누적 이동 평균 (Autoregressive Integrated Moving Average)의 약자

- 시계열 데이터의 과거 값과 오류를 사용하여 미래 값을 예측

- 이 모델은 자기회귀(AR), 차분(I), 이동평균(MA) 세 가지의 구성 요소로 이루어져 있음.

 

자기회귀(AR)

'자기회귀'는 과거의 값들이 미래 값에 어떤 영향을 미치는지를 설명한다.

예를 들어, 지난 주의 판매량이 이번 주의 판매량에 영향을 미치는 경우, 이는 자기 회귀 관계에 해당한다.

AR 부분에서는 'p'라는 파라미터를 사용하는데, 이는 과거 데이터 포인트 중 얼마나 많은 것을 고려할 것인지를 결정한다.

 

차분(I)

'차분'은 비정상적인 시계열 데이터를 정상적인 상태로 만들기 위해 사용된다.

비정상 시계열은 평균, 분산 등이 시간에 따라 변하는 특성을 가진다.

차분은 이러한 데이터의 추세나 계절성을 제거하여 시간에 따라 일정한 수준을 유지하도록 한다.

 

이동평균(MA)

'이동평균' 부분은 과거 예측 오차가 미래 값에 어떻게 영향을 미치는지를 나타낸다. 

MA에서는 'q'라는 파라미터를 사용하여 과거 예측 오차 중 몇 개를 고려할 것인지를 결정한다. 

model = ARIMA(train_data['평균기온'], order = (4, 3, 2))

 

위 코드는 ARIMA 모델을 초기화한다. 

여기서 train_data['평균기온']은 모델에 사용할 시계열 데이터이다.

order = (4, 3, 2)는 ARIMA 모델의 세 가지 주요 파라미터를 설정한다.

4, 3, 2는 각각 p,q,d를 의미하며

p는 자기회귀 부분의 차수, d는 차분의 차수, q는 이동평균 부분의 차수를 의미한다. 

 

 

시계열 데이터의 summary()

1. Log Likelihood

: 모델이 데이터를 얼마나 잘 적합하는지를 나타내는 지표, 이 값이 클수록 모델이 데이터를 더 잘 설명한다는 뜻 

 

2. AIC / BIC

: 모델의 적합도를 평가하고 모델 간 비교를 할 때 사용되는 지표이다. 낮은 값일 수록 모델의 적합성이 더 높음을 의미.

 

3. coef

: 이 계수는 AR과 MA 파라미터의 영향력을 나타낸다.

: 예를 들어, 하나의 계수가 3.21이라면, 계수가 양수이고 따라서 그것의 지연(lag) 값은 현재 값에 긍정적인 영향을 미친다는 뜻이다. 즉, 과거의 값이 높으면 현재 값도 높을 것으로 예상된다는 뜻이다.

 

4. P > |z|

: 각 계수의 통계적 유의미함을 나타내는 p-값입니다. 일반적으로 이 값이 낮으면 (예: 0.05 이하), 해당 계수가 통계적으로 유의미하다고 할 수 있다. 

 

5. Ljung-Box / Jarque-Bear / Heteroskedasticity(이분산성)

: 이 테스트들은 각각 잔차가 무작위 노이즈인지, 정규분포를 따르는지, 등분산성을 가지는지 평가한다.

 

6. Prob(Q, JB, H)

: p-값들이 낮다면(0.05 또는 0.01이하), 잔차가 무작위 노이즈의 특성을 가지며, 정규분포를 따르고, 시차에 따라 일정한 분산을 가진다고 볼 수 있다. 

 

배열의 정의

같은 종류의 많은 자료를 하나의 이름으로 저장하는 연속된 기억장소

 

 

1차원 배열 예시

//선언//

double avg[1000];
int age[5];

 

//선언과 동시에 초기화//

int d[6] = { 31, 28, 31, 30, 31, 30 };
int sum[100] = { 0 }; // 첫 원소에는 0으로, 부족한 초깃값은 무조건 0으로 초기화//
int a[] = {1, 2, 3, 4, 5}

 

여기서 주의해야할 점이 있다.

int sum[100] = {1}

 

만약 위와 같이 입력이 된다면 어떻게 될까? {1}이라면 첫 원소는 1로, 부족한 값은 0으로 초기화한다.

 

또, int a[ ] 만 입력해도 오류가 뜨기에 조심해야한다.

반드시 int a[]  = {숫자, 숫자, 숫자, 숫자 ...} 의 형식으로 써야한다.

 

//원소 참소(사용)//

printf("%d, %d, %d, %d, %d, %d \n", d[0], d[1], d[2], d[3], d[4], d[5]);
scanf("%d", &d[4]);

 

위와 같이 원소를 참조할 때 사용하는 [ ] 안의 첨자는 해당 원소가 배열 시작 위치로부터 몇 개 뒤의 원소인지를 의미함.

 

 

 

 


 

 

 

반복문을 이용한 배열처리

다음과 같이 코드를 만들어서 배열 안에 들어있는 값을 출력할 수 있으나,

int mid[4] = { 45, 37, 48, 26 };

	printf("%d점 \n", mid[0]);
	printf("%d점 \n", mid[1]);
	printf("%d점 \n", mid[2]);
	printf("%d점 \n", mid[3]);

 

자료의 개수가 100, 1000개 넘어가는 대량의 경우에는 굉장히 비효율적인 코드가 되기에

앞으로 반복문을 사용하여 배열을 처리하고자 한다.

 

그리하여 위의 코드를 반복문을 사용하여 표현하면 다음과 같다.

for (i = 0; i < 4; i++)
{
    printf("%d점 \n", mid[i]);
}

 

 

 

매크로 상수 정의를 통한 효율적인 배열 처리

지금까지 사용한 #include<stdio.h>는 전처리기 지시자로 이는 프로그램에서 사용하는 라이브러리 함수에 필요한 헤더파일을 전처리기 지시자 자리에 포함하기 위한 것이다.

이와 비슷하게 앞으로 배열을 다루는 코딩에서는 #define 전처리기 지시자를 사용하여 배열의 크기(원소 개수)를 매크로 상수로 정의해서 사용하는 것이 필수적이다.

 

다음의 예시를 보자.

#include <stdio.h>
#define N 4

int main()
{
	int mid[N] = { 45, 37, 48, 26 }, i;


	for (i = 0; i < N; i++)
	{
		printf("%d점 \n", mid[i]);
	}

	return 0;
}

 

여기서 stdio.h 밑에 define N  4로 코드가 적혀있는데 이것이 의미하는 것이 밑에 int main() 안에 있는 코드에서 사용되는 N은 무조건 4로 입력된다는 얘기이다. 그 말은 만약 배열의 크기가 4에서 10으로 바뀐다면 그저 #define N 4를 #define N 10으로 고쳐주면 된다는 얘기이다. 

 

매크로 상수 이름은 모두 대문자를 사용하는 것이 관습이다.

 

# 주의! 매크로 상수는 C명령문이 아니므로 끝에 ;을 넣지 않는다!!!

 

 

 

예시를 통해서 학습하기

 

1월 ~ 12월 열두 달 중 31일까지 있는 달만 출력하기 (조건에 맞는 원소만 출력하기)

#include <stdio.h>
#pragma warning (disable: 4996)
#pragma warning (disable: 6031) 
#define N 12

int main()
{
	int days[N] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, i;
	printf("31일까지 있는 달은");

	for (i = 0; i < N; i++)
	{
		if (days[i] == 31)
			printf(" %d월", i + 1);
	}
	
	printf("입니다.");

	return 0;
}

 

 

수강생 20명의 학년별 인원수 구하기(조건에 맞는 원소 개수 구하기)

#include <stdio.h>
#pragma warning (disable: 4996)
#pragma warning (disable: 6031) 
#define N 20

int main()
{
	int year[N] = { 1, 2, 2, 3, 4, 2, 3, 1, 3, 4, 2, 3, 3, 2, 3, 4, 3, 2, 2, 3 };
	int cnt1, cnt2, cnt3, cnt4, i;

	cnt1 = cnt2 = cnt3 = cnt4 = 0;
	for (i = 0; i < N; i++)
	{
		switch (year[i])
		{
			case 1: ++cnt1; break;
			case 2: ++cnt2; break;
			case 3: ++cnt3; break;
			case 4: ++cnt4; break;
		}
	}


	printf("%d학년: %d명\n", 1, cnt1);
	printf("%d학년: %d명\n", 2, cnt2);
	printf("%d학년: %d명\n", 3, cnt3);
	printf("%d학년: %d명\n", 4, cnt4);

	return 0;
}

 

 

배열의 평균과 중앙값 구하기 (직장인 11명의 평균 급여와 중앙값 구하기)

#include <stdio.h>
#pragma warning (disable: 4996)
#pragma warning (disable: 6031) 
#define N 11

int main()
{
	int pay[N] = { 1500, 675, 400, 375, 320, 315, 270, 235, 200, 170, 150 };
	int sum, mid, i;
	double median, avg_pay;

	sum = 0;
	for (i = 0; i < N; i++)
	{
		sum += pay[i];
	}
	
	avg_pay = (double) sum / 11;
	
	mid = N / 2;
	if (N % 2 == 0)
	{
		median = (pay[mid - 1] + pay[mid]) / 2.0;
	}
	else
	{
		median = pay[mid];
	}

	printf("평균    급여: %.1lf만원\n", avg_pay);
	printf("중앙값  급여: %.1lf만원", median);

	return 0;
}

 

 

판매가 5개 중 최저가 구하기

#include <stdio.h>
#pragma warning(disable: 4996)
#pragma warning(disable: 6031)
#define N 5

int main()
{
	int i, min, cost[N] = { 9500, 9350, 9450, 9100, 9300 };

	printf("5곳의 판매가: ");

	min = cost[0];
	for (i = 1; i < N; ++i)
	{
		printf("%d ", cost[i]);
		
		if (cost[i] < min)
		{
			min = cost[i];
		}
	}

	printf("최저가: %d", min);

	return 0;
}

 

 

수험번호를 입력하여 합격 여부 확인하기

int main()
{
	int i, input_no;
	int pass_no[N] = { 3011, 2011, 4012, 2014, 3017, 4004, 3004, 2007, 4026, 3019 };

	printf("확인할 수험번호 입력 : ");
	scanf("%d", &input_no);

	for (i = 0; i < N; i++)
	{
		if (pass_no[i] == input_no)
		{
			break;
		}
	}

	if (i < N)
	{
		printf("%d번은 합격입니다.", input_no);
	}

	else
	{
		printf("%d번은 불합격입니다.", input_no);
	}

	return 0;
}

 

 

배열에서 많이 하는 실수

잘못된 예 이유와 해결
int mid[5];
mid = {94, 53, 31, 56, 97};
int mid[5] =  {94, 53, 31, 56, 97}; 선언과 동시에 초기화!

for 문을 이용하여 각 원소의 값을 입력받거나 대입문 5개를 사용해 해결 가능하다. 
printf("%d점 \n", mid); 반복문을 사용하여 mid[0] ~ mid[4]까지 각 원소 출력을 반복해야한다.

for (i = 0; i < 5; i++)
{
    printf("%d점 \n", mid[i])';
}
int i, a[ ] = {92, 89, 73};

for (i = 1; i <= 3; i++)
    printf("%d점 ", a[i]);
결과가 이상하게 나온다.
배열 원소 첨자는 항상 0부터 시작!!
그렇기에 for(i = 0; i < 3; i++)으로 수정해야한다. 

'프로그래밍 > C,C++' 카테고리의 다른 글

인수 전달하지 않는 함수  (0) 2024.05.27
자료 배열 2 (9장)  (0) 2024.05.27
C,C++ - 제어문 (while, do~while문)  (0) 2024.04.08
C,C++ - 반복문  (0) 2024.04.03
C,C++ -switch문  (1) 2024.04.03
# 파일 불러오기 ====
Exam = read.table("/Users/user/OneDrive - 경북대학교/학과/2-1/탐색적자료분석 및 실험/실습파일/exam1.txt", head = T)
head(Exam$score)

# 줄기와 잎그림 확인 ====
stem(Exam$score)

# 줄기 수 줄이기와 늘이기 ====
# 이유는 여러가지 가능성을 열어두고 탐색하기 위함. 

## 줄기 수 줄이기 ====
stem(Exam$score, scale = 0.5)
# (0,1), (2,3).... 한 줄에 다 들어감.
# 이렇게하면 이전에 했던 줄기 그림이 쌍봉분포인데 비해 이것의 줄기 그림은 단봉분포의 형태를 취한다. 이것은 너무 단순하여 이 자료의 주요 특성을 잃은 것으로 볼 수도 있다. 즉 2개의 봉우리를 구분하지 못하고 1개만 본 것이다. 

## 줄기 수 늘이기 ====
stem(Exam$score, scale = 2)
# 원자료라면 하나였을 줄기가 각각이 줄기가 2개가 생김. 
# 일반적으로 줄기 수를 늘이면 늘일수록 많은 수의 봉우리를 보게 되고 반대로 줄기 수를 줄이면 줄일 수록 적은 수의 봉우리를 보게 된다. 

## hist ====
hist(Exam$score, nclass = 10, right = F)
# 대용량 크기 확인에 용이하다.

hist(Exam$score, nclass = 20, right = F)

 

 

줄기 그림과 히스토그램의 공통점과 차이점 

 

1. 공통점

 > 테두리가 동일: 각 구간의 관측빈도에 비례하는 길이의 막대 기둥을 가진다.

 

2. 차이점

 > 줄기 그림에서는 구간 내의 자료들이 숫자로 구별

   - 히스토그램에서는 보다 큰 정보의 손실이 발생함. 

 

 > 줄기 그림은 줄기의 크기를 줄이거나 늘이는데 작성된 줄기 그림 사용 가능 

   - 계획적인 시행착오를 수작으로 거듭할 필요가 있는 EDA에서는 효율성에서 차이가 있다.

 

 > 히스토그램은 임의로 구간의 폭을 지정할 수 있다. 

while문은 조건식의 값이 참이면 문장을 반복 수행하고 거짓이면 반복을 중단한다.

 

 

while문 기본형식

 

while(조건식)

    반복할 문장;

 

 

조건식은 참, 거짓으로 계산되는 수식으로 관계 연산자나 논리 연산자를 사용한 수식이 일반적이다.

 

 

예시

# pragma warning(disable : 4996)
# pragma warning(disable : 6031)
# include <stdio.h>
# include <math.h>

int main()
{
	int i, sum = 0;

	i = 1;
	while (i <= 10)
	{
		sum = sum + i;
		i = i + 1;
	}
	printf("1부터 %d까지의 합은 %d입니다.", i-1, sum);

	return 0;
}

 

cf) while문을 시작할 때 처음부터 조건식의 값이 거짓일 경우에는 본체가 한번도 실행되지 않을 수 있다. 

 

 

while문으로 무한루프 만들기

while문으로 무한루프를 만들려면 조건식에 항상 참인 값을 사용.

0이 아닌 값은 모두 참이지만 보통은 while(1)처럼 1을 사용한다.

위의 while문은 다음과 같인 변형될 수 있다.

무한 루프를 빠져나오기 위해서는 for문과 마찬가지로 탈출조건 필요(break)

while(1)
{
    if (i > 10) break;
    sum += i;
    mult *= i;
    i++;
}

 

 

무조건 한 번은 반복하기 do~while문

 

do

{

    반복할 문장;

} while (조건식);

 

do는 무조건 뒤에 {}(중괄호)가 필요하다.

i = 1;
do{
   printf("***\n")
} while (i <= 100);

 

이게 유용한 이유는

코드는 제어문이 많을수록 가독성과 디버깅에 좋지 않기 때문이다.

# pragma warning(disable : 4996)
# pragma warning(disable : 6031)
# include <stdio.h>
# include <math.h>

int main()
{
	while (1)
	{
		printf("양수를 입력하세요. ");
		scanf("%d", &n);
		if (n > 0)
			break;
	}
}

 

이것보다

# pragma warning(disable : 4996)
# pragma warning(disable : 6031)
# include <stdio.h>
# include <math.h>

int main()
{
	do
	{
		printf("양수를 입력하세요.");
		scnaf("%d", &n);
		
		if (n > 0)
			break;
	} while (n <= 0);
}

 

이게 더 좋은 코드 왜냐면 제어문이 전자는 2개이고 후자는 1개이기에 

 

 

continue문

반복문을 실행하다가 continue문을 만나게 되면 continue 다음에 있는 문장은 수행하지 않고 루프의 시작이나 끝부분으로 이동한다. 즉, for문이나 while문과 같은 반복문에서 continue를 만나면 for이나 while의 시작부분으로 돌아가 조건식부터 다시 검사하게 되며, do~while문에서 continue를 만나면 do~while문의 끝에 있는 조건식을 검사하고 루프를 반복한다. 

 

 

오늘 내용 총 복습할 수 있는 예시

# pragma warning(disable : 4996)
# pragma warning(disable : 6031)
# include <stdio.h>
# include <math.h>

int main()
{
	int n, cnt, sum;

	sum = 0;
	cnt = 1;
	
	while (cnt <= 5)
	{
		printf("양의 정수를 입력하세요. ");
		scanf("%d", &n);

		if (n >= 0)
		{
			printf("%d번째: 지금까지의 합 %d + %d = ", cnt, sum, n);
			sum = sum + n;
			cnt = cnt + 1;
			printf("%d\n\n", sum);
		}

	}
}

'프로그래밍 > C,C++' 카테고리의 다른 글

자료 배열 2 (9장)  (0) 2024.05.27
자료 배열 1 (8장)  (0) 2024.04.29
C,C++ - 반복문  (0) 2024.04.03
C,C++ -switch문  (1) 2024.04.03
C,C++ - 제어문(if)  (0) 2024.04.03

반복문

 

기본형식

for (i = 1; i <= 5; ++i)
{
	printf("(%d %d) \n", i, i+1);
}


for (i = 1; i <= 9; i += 2)
{
	printf("(%d %d) \n", i, i + 1);
}

for (i = 50; i > 0; i = i - 10)
{
	printf("%d\n", i);
}

for (i = 1; i <= 4; ++i)
{
	printf("%d / %d = %.2lf\n", i, i + 1, (double)i / i + 1);
}

 

 

예시

n 팩토리얼 구하기(for 문)

# pragma warning(disable : 4996)
# pragma warning(disable : 6031)
# include <stdio.h>
# include <math.h>

int main()
{
	int i, n, fac;

	printf("n! 구하기, n은(0≤n≤10)? ");
	scanf("%d", &n);

	fac = 1;
	for (i = 1; i <= n; ++i)
	{
		fac = fac * i;
	}
	printf("%d! = %d", n, fac);

	return 0;
}

 

 

# pragma warning(disable : 4996)
# pragma warning(disable : 6031)
# include <stdio.h>
# include <math.h>

int main()
{
	int i, n;

	printf("2~9 중 얼마? ");
	scanf("%d", &n);

	printf("\n");

	for (i = 0; i < n; ++i)
	{
		printf("C프로그래밍 언어\n");
	}

	printf("\n");

	for (i = 1; i <= n; ++i)
	{
		printf("(%d) ", i);
	}

	printf("\n\n");

	for (i = 100; i <= n * 100; i += 100)
	{
		printf("%d, ", i);
	}
	printf("끝");

	return 0;
}

 

 

# pragma warning(disable : 4996)
# pragma warning(disable : 6031)
# include <stdio.h>
# include <math.h>

int main()
{
	int n, i, sum;

	printf("1~n 중 홀수의 합 구하기\n");
	printf("n 입력: ");
	scanf("%d", &n);

	sum = 0;
	for (i = 1; i <= 10; i = i + 2)
	{
		sum += i;
	}
	printf("\n");
	printf("홀수의 합은 %d", sum);

	return 0;
}

 

 

 

'프로그래밍 > C,C++' 카테고리의 다른 글

자료 배열 1 (8장)  (0) 2024.04.29
C,C++ - 제어문 (while, do~while문)  (0) 2024.04.08
C,C++ -switch문  (1) 2024.04.03
C,C++ - 제어문(if)  (0) 2024.04.03
C,C++ - 다양한 연산  (0) 2024.04.03

case별로 특정 코드 실행하기

switch (식)
{
    case 상수값1; 코드1; break;
    case 상수값2; 코드2; break;
    case 상수값3; 코드3; break;

    default: 코드n;
}

 

(식)

  •  계산 결괏값이 정수형인 것만 가능하며, 'case'뒤에는 상수만 한 개 올 수 있음.(상수만 있는 식은 가능)
  • 문자 상수 'A'의 ASCII코드는 01000001이며, 논리값 참, 거짓은 정수 1, 0에 해당한다. 이처럼 문자 상수는 문자를 표현하는 코드 값이 정수이므로 '식' 결과가 문자형인 것도 사용 가능하며, '식' 결과가 논리값인 식 또한 가능하다.
  • 'case'값 역시 문자 상수나 논리값에 해당하는 정수를 사용하여 case 'A'; , case'+'; , case 1;, case 0; 으로 사용가능.

실행과정

  • 식을 계산하여 결괏값 구하기
  • 결괏값과 case 뒤의 값을 순서대로 비교하여 처음으로 일치하는 값을 만나면 그 뒤의 코드를 실행
  • 'break'를 만나면 switch문을 종료하고 다음 코드를 실행
  • 모든 'case'의 값과 비교하여도 같은 값이 없다면 'default'뒤의 코드를 실행
  • 'default: 코드n ' 부분은 필요하지 않다면 생략가능

주의

  • 특정 'case'의 코드를 실행할 때 'break'가 없으면 자동으로 다음 'case' 뒤의 코드를 실행하므로 switch문을 끝내고 싶다면 'break'를 사용해야함.
  • 위의 특징을 이용하면 다음과 같이 break를 사용하지 않음으로써 (식)이 상수1이거나 상수2이거나 상수3일 때 같은 코드를 실행할 수 있음.
case 상수1:
case 상수2:
case 상수3: 명령문1; 명령문2; ....; 명령문n; break;
  • 'case 상수1 || 상수2 || 상수3: 코드; break;'는 상수 중 한 개라도 0이 아닌 값이 있다면 or 연산 결과가 1이 되어 'case1; 코드; break;'와 같은 결과가 된다.

 

예시

# pragma warning(disable : 4996)
# pragma warning(disable : 6031)
# include <stdio.h>

int main()
{
	int n;

	printf("주민등록번호 일곱 번째 숫자는?");
	scanf("%d", &n);

	switch (n)
	{
		case 1: printf("1900년대 출생 남자입니다.\n"); break;
		case 2: printf("1900년대 출생 여자입니다.\n"); break;
		case 3: printf("2000년대 출생 남자입니다.\n"); break;
		case 4: printf("2000년대 출생 여자입니다.\n"); break;

		default: printf("고려 대상이 아닙니다.\n");
	}

	return 0;
}

 

# pragma warning(disable : 4996)
# pragma warning(disable : 6031)
# include <stdio.h>

int main()
{
	int n;

	printf("주민등록번호 일곱 번째 숫자는?");
	scanf("%d", &n);

	switch (n)
	{
		case 1: 
		case 3: printf("남자입니다.\n"); break;
		case 2: 
		case 4: printf("여자입니다.\n"); break;

		default: printf("고려 대상이 아닙니다.\n");
	}

	return 0;
}

'프로그래밍 > C,C++' 카테고리의 다른 글

C,C++ - 제어문 (while, do~while문)  (0) 2024.04.08
C,C++ - 반복문  (0) 2024.04.03
C,C++ - 제어문(if)  (0) 2024.04.03
C,C++ - 다양한 연산  (0) 2024.04.03
C,C++ - 입력함수 scanf()  (0) 2024.04.02

if문

 

if는 직관적이기에 예시로 습득하는 것이 좋을 듯하다.

 

예시

# pragma warning(disable : 4996)
# pragma warning(disable : 6031)
# include <stdio.h>

int main()
{
	int year;

	printf("2월이 며칠까지 있는지 궁금한 연도: ");
	scanf("%d", &year);

	printf("%d년 2월은 ", year);

	if ((year % 400 == 0) || (year % 4 == 0) && (year % 100 != 0))
	{
		printf("29일까지 있습니다.\n");
	}
	else
	{
		printf("28일까지 있습니다.\n");
	}

	return 0;
}

 

{} 안의 코드는 한 탭 안으로 들여쓰기를 하는 것이 보기 좋다.

{}코드 블록은 코드가 한 문장이라면 {} 생략 가능하다.

 

주의!

if(조건);이나 else;와 같이 뒤에 ;을 사용하면 ';'만 있는 빈 문장이 있는 것으로 간주하여 잘못된 결과가 나오거나 오류가 발생한다.

 

 

if의 중첩

# pragma warning(disable : 4996)
# pragma warning(disable : 6031)
# include <stdio.h>

int main()
{
	int month;

	printf("몇 월? ");
	scanf("%d", &month);

	if (month <= 6)
	{
		if (month <= 3)
		{
			printf("상반기 일사분기");
		}
		else
		{
			printf("상반기 이사분기");
		}
	}
	else
	{
		if (month <= 9)
		{
			printf("하반기 삼사분기");
		}
		else
		{
			printf("하반기 사사분기");
		}
	}

	return 0;
}

 

else 바로 뒤에 if가 있는 구조

# pragma warning(disable : 4996)
# pragma warning(disable : 6031)
# include <stdio.h>

int main()
{
	int year;

	printf("학년은? ");
	scanf("%d", &year);

	if (year == 1)
	{
		printf("Freshman");
	}
	else if (year == 2)
	{
		printf("Sophomore");
	}
	else if (year == 3)
	{
		printf("Junior!");
	}
	else if (year == 4)
	{
		printf("Senior!");
	}
	else
	{
		printf("잘못된 학년");
	}

	return 0;
}

 

 

'프로그래밍 > C,C++' 카테고리의 다른 글

C,C++ - 반복문  (0) 2024.04.03
C,C++ -switch문  (1) 2024.04.03
C,C++ - 다양한 연산  (0) 2024.04.03
C,C++ - 입력함수 scanf()  (0) 2024.04.02
C,C++ - 필드폭과 정밀도 지정  (0) 2024.04.02

기본연산자

산술연산자 기능 사용 예 연산의 결과
+ 더하기 5+3 8
- 빼기 5-3 2
* 곱하기 5*3 15
/ 몫 구하기(정수일 때만) 5/3 1
나머지 구하기 5%3 2

 

증감연산자

종류 증감연산자 연산의 결과
전위형(prefix) ++x x값을 먼저 1증가시킨 후 연산에 사용되며 결과값은 1 증가한 x값이다.
--x x값을 먼저 1감소시킨 후 연산에 사용되며 결과값은 1 감소한 x값이다.
후위형(postfix) x++ x값을 먼저 연산에 사용한 후, 값을 1증가시키며 결과값은 증가하지 않은 원래의 x값이다.
x-- x값을 먼저 연산에 사용한 후, 값을 감소시키며 결과값은 감소하지 않은 원래의 x값이다. 

 

예시

#pragma warning (disable:4996)					
#pragma warning (disable:6031)	
#include <math.h>
#include <stdio.h>		

int main()
{
	int x = 10, y = 20, z = 30;

	x = ++x * 5;
	y = y++ * 5;
	z = 5 - --z;

	printf("x = %d\n", x);
	printf("y = %d\n", y);
	printf("z = %d\n", z);

	return 0;
}

 

결과

 

복합대입연산자

파이썬에서 사용했던 복합연산자와 비슷하다. (+=, -=, *=)

cf) 복합 대입 연산자를 다른 연산자와 함께 사용할 때는 주의해야한다. 복합 대입 연산자는 다른 연산자에 비해 우선 순위가 낮으므로 생각지 못한 결과가 나올 수 있다.

 

예시

int x = 2;
x = x * 3 + 2; //결과 : 8
x *= 3 + 2;  //결과: 10

 

 

관계연산자

관계연산자 의미 연산의 결과
x > y x가 y보다 큰가? 0
x >= y x가 y보다 크거나 같은가? 0
x < y x가 y보다 작은가? 1
x <= y x가 y보다 작거나 같은가? 1
x == y x가 y와 같은가? 0
x != y x가 y와 같지 않은가? 1

 

+ C언어에서 참과 거짓

  • 1) 논리값을 수치로 변환하는 규칙
  • 2) 수치를 논리값으로 변환하는 규칙

1)

논리값 수치
1
거짓 0

 

2)

수치 논리값
0이외의 값
0 거짓

 

 

논리연산자

x y 논리곱(AND) 논리합(OR) 논리부정(NOT)
x && y x || y !x
0 0 0 0 1
0 1 0 1 1
1 0 0 1 0
1 1 1 1 0

 

 

논리연산자의 단축 평가

 

(2 > 5) && (x < 3)

> && 앞의 논리값 (2 > 5)이 거짓이므로 뒤에 어떤 논리값이 나타나더라도 전체 연산의 결과는 거짓이다. 따라서 더 이상 뒤의 논리값(x < 3)을 평가하지 않는다. 

 

(2 < 5) || (x < 3)

> || 앞의 논리값 (2 < 5)이 참이므로 뒤에 어떤 논리값이 나타나더라도 전체 연산의 결과는 거짓이다. 따라서 더 이상 뒤의 논리값(x < 3)을 평가하지 않는다.

 

예시

#pragma warning (disable:4996)					
#pragma warning (disable:6031)	
#include <math.h>
#include <stdio.h>		

int main()
{
	int x = 1, y = 2;
	int result = (x < 10) || (y = x * 3);

	printf("%d\n", y);

	return 0;
}

결과

 

우리는 y에 3이 찍힐 것이라고 기대했는데 출력해보니 2가 나왔다.

result의 (x < 10)에서 이미 참이기 때문에 뒤에 연산을 해주지 않은 것이다. 

(|| 가 &&로 바뀌면 3이 출력된다.)

 

형변환 연산자

자동형변환

자동 형변환은 프로그래머가 따로 지정하지 않아도 컴파일러에 의해서 자동으로 처리되는 형변환

예를 들어 '정수 + 실수'와 같이 피연산자의 데이터 형이 다르면 자동으로 형변환이 일어나서 피연산자의 데이터형을 같게 만든 다음 필요한 연산을 수행한다. 이때, 정수형 연산은 char, short형은 int형으로 실수형 연산은 float형을 double형으로 자동변환해서 처리한다. 이처럼 작은 크기(1byte, 2byte)의 데이터형을 큰 크기(4byte)의 데이터형으로 변환하는 것을 형넓힘 변환이라고 한다. 

int i = 100;
float j = 1.23;
printf("%.2f", i + j); //i는 float로 자동 변환되어 float + float 연산을 수행한다.

 

대입연산의 경우 형좁힘이 발생할 수 있다.

int i;
i = 3.14; 

// 3.14를 int형으로 변환하면서 소수점이하를 잘라버리고 변수 i에 저장한다.
// 이와 같이 형변환 시 값의 일부가 사라질 때는 컴파일러가 경고 메시지를 보여준다.

 

강제형변환 

(int) 3.14
(float) sum

 

예시

# pragma warning(disable : 4996)
# pragma warning(disable : 6031)
# include <stdio.h>

int main()
{
	int x = 7, y = 2;
	double result = (double)x / y; 
	int c = (double)x / y;
	printf("(float)x / y = %.1lf\n", (float)x / y);

	x = 5.4 + 3.0;
	y = (int)5.4 + (int)1.2;
	printf("x = 5.4 + 3.0 = %d\n", x);
	printf("y = (int)5.4 + (int)1.2 = %d\n", y);
	printf("%.1lf\n", result);
	printf("%d", c);

	return 0;
}

결과

 

연산자의 우선순위

수학의 연산을 따른다.

(우선순위 중간에 빈 숫자들은 지금 이걸 배우는 단계에서는 크게 중요하지 않아 나중에 다뤄보고자한다.)

우선순위 분류 연산자 결합규칙
1 단항 () [] ->
2 ++ -- + - sizeof ~ ! * &
3 산술 * / %
4 + -
6 관계  < <= > >=
7 == !=
11 논리 &&
12 ||
14 대입 = += -= *= /= %= &= |= ^=
<<= >>=

 

 

예제

시간 계산 프로그램

# pragma warning(disable : 4996)
# pragma warning(disable : 6031)
# include <stdio.h>

int main()
{
	int sec;

	printf("초(sec) 입력 : ");
	scanf("%d", &sec);

	int s, m, h;

	s = sec % 60;
	m = sec / 60 % 60;
	h = sec / 60 / 60;
	
	printf("입력한 %d초는 %d시간 %d분 %d초입니다.", sec, h, m, s);

	return 0;
}

결과

 

'프로그래밍 > C,C++' 카테고리의 다른 글

C,C++ -switch문  (1) 2024.04.03
C,C++ - 제어문(if)  (0) 2024.04.03
C,C++ - 입력함수 scanf()  (0) 2024.04.02
C,C++ - 필드폭과 정밀도 지정  (0) 2024.04.02
C, C++ - 변수 생성  (0) 2024.04.01

+ Recent posts