레야몬

3장: 코딩과 디버거에 관하여 - 3 (63p ~ 87p) 본문

알고리즘/Algorithmic Problem Solving Strategies

3장: 코딩과 디버거에 관하여 - 3 (63p ~ 87p)

Leyamon 2022. 10. 19. 17:45

변수 범위의 이해

<산술 오버플로>

너무 큰 결과

  • 32비트 자료형의 범위를 넘어가면 64비트 자료형을 사용하면 되지만 64비트 자료형을 전달하는 과정에서 32비트 자료형을 사용하는 실수를 범하기 쉬우므로 조심하자.

너무 큰 중간 값

  • 변수들의 크기는 작지면, 곱하거나, 제곱하는 과정에서 오버플로우가 일어날 수 있으므로 조심해야 한다.

너무 큰 '무한대' 값

  • INF값을 사용할 때 더하거나 곱하는 과정에서 오버플로우가 날 수 있으므로 조심해야 한다. INF는 987654321로 하는 것을 추천한다.

오버플로 피해 가기

  • 오버플로가 발생하는 것을 알았을 때 이를 해결하는 방법은 여러 가지가 있다.
    1. 더 큰 자료형을 사용하는 방법(32비트 자료형 -> 64비트 자료형)
    2. 계산 순서를 바꾸는 방법( a*b/c -> a/c*b )
    3. 계산 방법을 다르게 해 피해 가는 방법(nCr -> n-1Cr-1 + n-1Cr)

자료형의 프로모션

  • 피연산자의 자료형이 다를 때 같은 자료형으로 변환해서 계산하는데 이를 프로모션이라고 한다. unsigned를 다른 자료형과 계산할 경우 signed도 unsigned로 변환되므로 이를 조심해야 한다. 특히 .size()의 경우 unsigned long long을 반환하므로 조심해야 한다. (int).size()로 하는 것을 추천한다.

 

<실수 자료형의 이해>

부동 소수점 표기

  • 부동 소수점 표기법은 소수점이 둥둥 떠다닌다, 즉 소수점이 움직이는 표기법이다. 실수는 2진수로 표기되는데 소수점 아래는 1/2, 1/4, 1/8,... 의 크기를 가진 2진수로 표기된다.
  • 부동 소수점은 부호 비트(sign bit), 지수(exponent), 가수(mantissa)로 이뤄지는데 부호 비트는 +, -. 지수는 소수점의 위치, 가수는 소수점을 옮긴 실수의 최상위 X비트이다. 지수보다는 가수에 맞추는 편이 일상생활에 맞고 정확도를 높일 수 있기 때문에 지수보다는 가수에 더 많은 비트를 사용한다.

실수 자료형

 

실수 비교하기

  • 실수를 저장하는 것은 정확한 값이 아닌 최대한 근사한 값을 저장하므로 실수를 정확히 같다고 판단하는 것은 어렵다. 그래서 \(10^{-10}\) 보다 차이가 작다면 같은 실수로 판단하는 것으로 실수의 같음을 판단할 수 있다. 그러나 오차가 큰 것을 곱해서 오차를 더 키우는 등의 오차가 많이 큰 경우에는 이도 안전하지 않다. 이를 해결할 수 있는 방법은 크게 두 가지가 있다.
  • 비교할 실수의 크기들에 비례한 오차 한도를 정하는 것인데, 두 수가 같다고 판정할 수 있으려면 오차 한도 값이 두 수의 차이의 최댓값보다 커야 하며 두 수가 다르다고 판정하려면 두 수가 다르다고 판정할 값보다는 오차 한도 값이 작아야 한다. 이런 적절한 오차 한도 값을 정하면 안정적인 실수 비교가 가능하다.
  • 상대 오차를 이용하는 것인데

$$ relativeErrpr(a, b) = \frac{\left|a-b \right|}{max(\left|a \right|, \left|b \right|)} $$

  • 이렇게 계산한 두 수의 상대 오차는 두 수의 크기와 상관없이 판단할 수 있다. 그러나 매우 작은 숫자의 경우 relativeError(0, x) = x/x = 1로 다르다고 판단하는데 이는 같다고 판단해야 하므로 위 방법보다 더 작은 오차 범위보다 작다면 같다고 판단하는 것을 추가해준다.
  • 대소를 비교할 때는 오차 때문에 같은 값에서 오히려 크다, 작다가 판단될 수 있으므로 항상 두 값이 같은 경우, 즉 두 값이 아주 가까운 경우를 먼저 확인하고 처리해야 한다.

정확한 사칙연산

  • 가수부가 52비트이므로 이보다 작게 표현할 수 있는 실수들은 항상 정확하게 표현할 수 있다. 이렇지 않은 경우에는 유리수의 경우 분모와 분자를 따로 계산함으로써 정확한 사칙연산을 수행할 수 있고, 또는 십진수 클래스를 사용할 수 있다.

코드의 수치적 안정성 파악하기

  • 코드를 계속 실행시킬 때 오차가 더 이상 커지지 않는 다면 안정적(numerically stable)인 프로그램이라고 한다. 이 경우에는 실수의 오차를 생각하지 않아도 상관이 없지만, 안정적이지 않은(numerically unstable) 프로그램의 경우(0.00001의 오차가 13245의 오차로 커지는 경우)이는 실수를 다룰 때 위의 기능을 고려하여 구현하여야 한다.

실수 연산 아예 하지 않기

  • 실수 연산은 최대한 피하는 것이 좋다. 예를 들어 a/b*c를 a*c/b로 바꾸거나, 두 점 사이의 거리를 구하는 대신에 제곱을 구하는 것, 또는 실수 좌표를 써야 하는 기하에서 가로 세로에 정수배를 곱하는 것으로 정수만으로 문제를 풀 수 있게 된다.

 

 

 

 

 

 

 

 

 

 

 

※현재 고등학교 등교 중인 학생입니다. 이제 알고리즘을 본격적으로 공부하기 시작해서 아직 초보입니다. 혹시 제가 잘못 알고 있는 점이나 더 좋은 풀이 방법이 있어 댓글에 남겨주시면 감사히 하나하나 열심히 읽어보겠습니다. 좋아요, 단순한 댓글 한마디라도 저에겐 큰 힘이 됩니다! 감사합니다.

Comments