[C#] if (1.1f == 1.1) ...?

Lingtea_luv·2025년 3월 12일
0

C#

목록 보기
2/37
post-thumbnail

연산자


요약 : 데이터를 원하는대로 가공하기 위한 도구

컴퓨터는 결국 연산하는 기계이기에 우리는 컴퓨터에게 기본 연산을 지시할 수 있다. 그 지시에 필요한 도구가 연산자라고 생각하면 된다.

학습 목표

  • 연산자의 이해
  • 변수 간의 연산 방법 숙지

산술 연산자

  • 더하기, 빼기, 곱하기
    기존 사칙연산과 규칙이 동일하다.
  	Console.WriteLine(1.1f + 0.3f);   // output : 1.4000001

주의할 점 : 내 입장에서 당연한 결과값이 컴퓨터에게는 그렇지 않을 수 있다는 것
컴퓨터의 기본 연산은 이진법으로 이루어지기 때문에 1.1f와 0.3f의 정확한 표현이 불가능하다.
따라서 연산 과정에서 메모리 플로우가 발생할 수 있기에 정확한 연산이 필요한 곳에서는 decimal의 형태로 연산을 한다. 게임 개발 과정에서는 근소한 오차는 무시하고 속도를 중요시하기 때문에 int를 선호한다.


  • 정수 간의 연산 결과는 반환값의 자료형이 정수 형태가 되어 소수점 이하를 버린다.
  Console.WriteLine(5 / 2);    // output : 2
  Console.WriteLine(5 / 2f);   // output : 2.5

만약 연산에 포함된 데이터 중 하나라도 float 형태라면 반환값도 float 형태로 출력된다.

만약 주어지는 값이 정수일 수 밖에 없지만, 결과값으로 float를 받아야하는 경우면 어떻게 할까?

  int award = 9;
  int partyMem = 4;
  Console.WriteLine(award / partyMem);  // output : 2
  Console.WriteLine((float)award / partyMem);  // output : 2.25

보상과 파티원 인원은 정수일 수 밖에 없지만 반환된 값은 소수점이 나와 float 형태로 데이터를 출력할 필요가 있다. 이 경우 (자료형)데이터 의 방식으로 형변환을 하여 임시로 데이터의 형태를 바꿔, 반환값을 해당 데이터 형태로 출력할 수 있다.

  float a = 9.8;
  float b = 4;
  Console.WriteLine((int)a / b);   / output : 2.45
  Console.WriteLine(a / (int)b);   / output : 2.45

단, 형변환시 순서가 중요해지는 경우가 있는데 위에서 3번째, 4번째 코드의 출력되는 값은 동일하지만 계산 순서가 다르다.

  • 나머지
    소수점 이하가 버려지는 경우 추가로 나머지 연산자(%)의 사용이 필요하다.

나머지 연산자(%)를 언제 쓰는데?

가장 쉬운 예시로는 자릿수를 구할 때 쓴다.

  Console.WriteLine(294567 % 10);           // output : 7
  Console.WriteLine(294567 / 10 % 10);      // output : 6
  Console.WriteLine(294567 / 100 % 10);     // output : 5

위에서부터 1의 자리 / 10의 자리 / 100의 자리의 자릿수를 구할 수 있다. 물론 다른 곳에서도 나머지 연산자의 활용이 필요하고, 특히 게임 개발에서 유용하게 활용된다고 한다.

대입 연산자

요약 : 변수 등의 데이터 공간에 데이터 값을 할당하는 연산자

  int a = 10;
  10 = 10;

첫 번째 코드는 정수형 a라는 데이터 공간에 10이라는 데이터 값을 할당한 것이다. 해당 코드는 문제가 없으나, 두 번째 코드의 경우 좌변의 10은 데이터 값으로 데이터 공간이 존재하지않기 때문에 버그가 발생하는 것을 볼 수 있다.

  • 복합 대입(할당) 연산자
  int a;
  a += 1;
  a = a + 1;

대입 연산자 = 가 단순히 데이터 값을 할당하는 것이었다면, 복합 대입의 경우 두 번째 코드와 같이 +나 -를 = 앞에 붙여 단순 연산과 함께 데이터 값을 할당하는 것이다. 예를 들어 위의 코드에서 2,3번째의 결과값은 동일하다.

비교 연산자

  int a = 3;
  int b = 4;
  bool comp = a > b

간단히 두 데이터를 비교하기 위해 사용되는 연산자이다.
다만 비교 연산자로 반환된 데이터는 불린 값으로 bool 로 저장하여 조건문 등에 활용한다.

논리 연산자

  int leftMission = 4;
  int leftMafia = 0;
  if (leftMafia == 0 || leftMission == 0)
  {
  	Console.WriteLine("시민이 승리하였습니다");
  }

어몽어스 게임에서 시민의 승리조건은 남은 미션이 없거나 마피아를 모두 검거한 경우이다.
즉 2가지의 조건 중에 하나만 달성해도 시민이 승리하는데, 이를 표현한 코드가 위와 같다.
이처럼 2개 이상의 조건의 불린 값으로 연산을 할 때 사용하는 것이 논리 연산자이다.

  • 논리합( | | ) : 조건을 or 로 연결, 명제가 하나라도 참인 경우 true 반환
  • 논리곱(&&) : 조건을 and 로 연결, 명제 모두 참인 경우 true 반환
  • 부정( ! ) : 조건의 논리값을 부정하여 반환 (true -> false)

단항 연산자

  int level = 0;
  level += 1;
  ++level;
  level++;
  
  level = -level;

특수하게 값이 1씩 증가하거나 감소하는 경우, 혹은 값의 부호를 바꾸는 경우 간단하게 표현이 가능하며, 이를 총칭 단항 연산자라고 한다.

  • 전위 연산자
  int iValue = 0;
  Console.WriteLine(++ivalue);  // output : 1

값을 반환하기 전에 연산 = 연산하고 난 후의 값을 출력한다.

  • 후위 연산자
  int iValue = 0;
  Console.WriteLine(ivalue++);  // output : 0

값을 반환한 후에 연산 = 연산하기 전의 값을 출력한다.

문자열 연산

아래 코드의 결과로 출력되는 값은 무엇일까?

  Console.WriteLine("정수 더하기 {0}", 20 + 1);       // output : 21
  Console.WriteLine("문자열 더하기 {0}", "20" + 1);   // output : 201

정수 데이터의 덧셈 연산의 결과는 정수 데이터로 반환되지만, 덧셈 연산에 문자열 데이터가 포함된 경우 결과는 문자열 데이터로 연산되어 반환된다. 즉, 단순히 문자열을 이어붙인 형태로 나타난다.
다만, 게임 개발의 경우 문자열의 연산은 실수가 쉽고 비효율적인 연산이기에 최적화의 문제가 있어 사용하지 않는다.

  string age;
  age = Console.ReadLine();                            // input : 23
  age = age + 1;
  Console.WriteLine(당신의 다음 년도 나이 : {0}", age);  // output : 231

따라서 위의 코드의 경우 내가 입력한 값은 숫자이지만 해당 값을 저장한 데이터 공간 형태는 string인 문자열이기 때문에, 23을 입력했을 때 출력되는 데이터는 24가 아닌 231이 된다.

  • 문자열 보간
  int age = 23;
  Console.WriteLine("당신의 나이는 {0} 입니다.",age);
  Console.WriteLine($"당신의 나이는 {age} 입니다.");

저번에 배운 자리표시자를 $ 의 활용으로 조금 더 직관적인 문자열 작성이 가능하다.
문자열 앞에 $ 을 쓰게 되면 데이터를 {데이터 이름} 처럼 문자열에 포함하는 것이 가능해져, 자리의 위치와 순서대로 데이터를 입력하는 것 없이 간편하게 쓸 수 있다.
따라서 위에서 출력되는 결과는 동일하다.

참고 기능


region

visual studio 내에서 블록을 설정하고 싶을 때 사용한다. 객체 설정 이후 #region #endregion을 통해 객체 별로 블록을 나눈다면, 가시성에 도움이 될 것 같다.

ReadLine

  string name
  Console.Write("이름을 입력하세요 : ");
  name = Console.ReadLine();
  Console.WriteLine("{0}님 환영합니다.", name);

WriteLine이 컴퓨터가 처리한 값을 우리에게 출력하는 함수라면, ReadLine은 우리가 특정 값을 컴퓨터에게 입력하는 함수이다. 당연히 입력한 값을 변수 등의 데이터 공간에 할당하는 것이 가능하다. 다만, 문자열 형태(string)로만 할당할 수 있다.
위처럼 ReadLine과 WriteLine을 통해 컴퓨터가 나랑 대화하는 듯한 기분을 낼 수 있다.

데이터 형태 변환

  Console.Write("나이를 입력해주세요 : ");
  string input = Console.ReadLine();              // input : 23
  int age = int.Parse(input);       
  Console.WriteLine($"입력하신 나이 : {age}");     // output : 23
  Console.WriteLine($"다음년도 나이 : {age + 1}"); // output : 24

이전에는 ReadLine으로 입력한 데이터가 string으로 저장되어 문자열 연산으로 output이 출력되었지만, int.Parse 함수를 통해 string 데이터가 int로 형태 변환되어 output이 숫자 연산을 통해 24가 출력되는 것을 볼 수 있다.

  • TryParse
    개발자의 숙명 같은건데, 모든 유저가 내가 원하는대로 행동해주지 않는다는 것을 명심해야한다.
    물론 나도 어렸을 때 카트x이더 게임할 때 벽에 비벼서 맵을 통과해본 적이 있으니 자업자득인 셈.
  int age = int.Parse(Console.ReadLine());

만약 위처럼 유저의 나이를 얻기 위해 ReadLine 함수를 사용할 경우, 과연 유저들이 숫자로 입력할까?
삼십육으로 작성하는 사람도 있을 것이고, 악질인 경우에는 니얼굴까지 입력되는 것을 볼 수 있을지도 모른다.
결국 유저들의 수준을 간과했던 우리는 버그를 수집하게되는데, 이를 방지하기 위한 함수가 TryParse이다.

  int money;
  int.TryParse(Console.ReadLine(), out money);
  Console.WriteLine("보유하고 있는 골드 : {money}");

TryParse를 간단히 말하면 변환을 시도해보고 가능하면 변환을 하고, 불가능하면 0으로 써주는 방식이다.
예를 들어 위 코드의 input이 23인 경우 output도 23으로 나오지만, input이 니얼굴인 경우 output은 0으로 나온다.

그럼 만약에 유저가 0을 입력한거면? 0골드인거랑 어떻게 구분해?

이를 위해 TryParse의 값을 bool로 저장하여 구분한다.

  int money;
  bool success = int.TryParse(Console.ReadLine(), out money);
  Console.WriteLine("보유하고 있는 골드 : {money}");
  Console.WriteLine(success);

int.TryParse는 money의 데이터를 string에서 int로 변환해주는데, 이때 int.TryParse의 값 자체는 bool의 형태로 저장이 가능하다. 형태 변환이 제대로 이루어졌다면 true, 제대로 이루어지지않았다면 false가 되는 것이다.
따라서 만약 유저가 0을 입력한다면 출력값은 0, true가 되고, 니얼굴을 입력한다면 0, false가 되어 구분이 가능하다.

  • Convert
  string toConvert = "2324";
  int converted;
  converted = Convert.ToInt32(toConvert);
  Console.WriteLine(converted + 10);         // output : 2334

Convert.ToInt32 함수는 변환하고자 하는 문자열 데이터를 비교적 간편하게 정수형 데이터로 변환이 가능하다.
다만 문자열이 숫자로 이루어진 경우가 아니면 버그가 발생하기 때문에 TryParse를 사용하는 것이 좋다.

조건문


학습 목표

  • if, else if, else 문의 이해
  • 조건문의 사용 사례의 이해
  • 조건문의 활용 실전 숙지

if 조건문

  if(true)
  {
  	Console.WriteLine("응 맞아");
  }
  
  응 맞아

if 함수의 경우 ( ) 안의 조건이 true인 경우 { } 안의 기능이 수행되고, 조건이 false인 경우 기능이 수행되지 않는다.
따라서 위의 코드를 실행시키면 "응 맞아" 가 출력되는 것을 볼 수 있다.

  bool alive;
  int hp = 100;
  int damage;
  damage = int.Parse(Console.ReadLine());   // input : 30
  hp = hp - damage;
  alive = hp > 0
  
  if(alive)
  {
  	Console.WriteLine("플레이어는 아직 살아있습니다");
  }
  
  플레이어는 아직 살아있습니다

이번에는 Console.ReadLine 을 활용해서 입력받은 정보를 활용해서 조건문을 작성해보자.
위 코드에서 hp보다 damage가 낮으면 if의 조건이 true가 되어, input이 30인 경우 아래와 같이 해당 문장을 출력하는 것을 볼 수 있다.

else if 조건문

컴퓨터가 가위를 냈다고 가정하고 가위바위보를 해보자.

Console.Write("가위 바위 보!!!" : );
string playerChoice = Console.ReadLine();

if(playerChoice == "바위")
{
	Console.WriteLine("이겼습니다!");
}

else if(playerChoice == "가위")
{
  Console.WriteLine("비겼습니다");
}

else if(playerChoice == "보")
{
  Console.WriteLine("졌습니다");
}

else
{
	Console.WriteLine("잘못 입력하셨습니다");
}

위의 코드를 해석하면 다음과 같다.

만약 내가 바위를 내면 이길 것이고
바위를 안 내고 가위를 낸다면 비길 것이고
바위, 가위도 아니고 보를 낸다면 질 것이다.
셋 중 하나에 해당되지 않는 경우에는 잘못 입력한 것이다.

if ( ) 안의 조건이 false인 경우 다음 else if의 조건에 대입하여 true / false 여부를 판단한다.
else는 남은 경우를 모두 묶어 true 취급을 하며 { } 안의 기능을 실행한다.

참고로 반대 과정을 pseudo code라고 한다.

  • 주의사항

    if 조건문은 순차적으로 실행이 되기 때문에, 조건의 범위가 작은 것부터 적어야한다.
    그렇지 않으면 상위 조건문의 조건에서 false가 되었을 경우 하위 조건문에서도 자동으로 false가 되어버리기 때문이다.

Switch 조건문

wasd로 움직이는 캐릭터의 행동 스크립트(알고리즘)는 다음과 같이 간략하게 구현할 수 있다.

  string input;
  input = Console.ReadLine();
  char inputInt;
  char.TryParse(input, out inputInt);
  switch(inputInt)
  {
  	case 'w' : 
  		Console.WriteLine("앞으로 1칸 이동합니다");
  		break;
    case 'a' : 
  		Console.WriteLine("왼쪽으로 1칸 이동합니다");
  		break;
  	case 's' : 
  		Console.WriteLine("뒤로 1칸 이동합니다");
  		break;  
  	case 'd' : 
  		Console.WriteLine("오른쪽으로 1칸 이동합니다");
  		break; 
  	default : 
  		Console.WriteLine("허가되지 않은 행동입니다.");
  		break;
  }

switch 조건문은 값의 일치 여부에 따라 기능을 실행한다는 점에서 if 조건문과 차이가 있다.
switch 조건문으로 만드는 기능을 if 조건문으로 구현시킬 수 있으나, 추가 키를 입력해야할 때의 편함과 코드 가독성을 위해 switch 조건문을 사용하는 경우가 많다.
코드를 공유하여 작업하는 경우가 많은 게임 개발에서는 switch 조건문과 if 조건문을 유연히 사용할 필요가 있다.

profile
뚠뚠뚠뚠

0개의 댓글