hyei-devlog

[Python/파이썬] 백준 1312 소수 본문

Online Judge/Baekjoon

[Python/파이썬] 백준 1312 소수

winter126 2025. 2. 25. 01:37

📍 문제

https://www.acmicpc.net/problem/1312

백준 1312 소수

 

📍 전체 코드

A, B, N = map(int, input().split())

num = A * (10 ** N) // B
digit = num % 10

print(digit)

 

📍 문제 풀이

num = A * (10 ** N) // B

 

분자 A에 10의 N제곱을 곱하여, 소수점 아래 N자리까지 미리 확장한다.

예를 들어, N=3이라면 A를 1000배 확장하는 것이다.

 

그 후, B로 나누는 연산을 정수 나누기(//)로 수행한다. 이렇게하면 소수점 이하 자리에서 원하는 값만 남게 된다. 

 

digit = num % 10

 

num을 10으로 나눈 나머지를 구하는 연산을 통해 소수점 N번째 자리의 숫자를 추출할 수 있다.

 

📍 문제 해결 위한 고민

num = (A / B) * (10 ** N)
digit = int(num) % 10

 

처음에 이렇게 풀었는데, 런타임 에러가 났다 ^^

 

알고보니 저렇게 풀면 부동소수점 연산 오차가 발생한다고 한다. 

 

부동소수점 숫자는 컴퓨터가 실수를 표현하는 방식인데, 모든 실수를 정확하게 표현할 수 없기 때문에 일부 소수점 자리에서 오차가 발생할 수 있다. 특히 유리수(예: 1/3)가 무한 소수일 때 컴퓨터는 이를 근사값으로 저장한다.

 

예시)

A = 1
B = 3
N = 20

num = (A / B) * (10 ** N)  # (1 / 3) * 10^20
print(num)  # 33333333333333333120.0 (근사값)

 

1 / 3은 정확히 0.333333... (무한 소수)이다. 하지만 컴퓨터는 이 값을 근사값으로 저장해야 하기 때문에 0.3333333333333333과 같은 근사값이 저장된다. 이 값은 실제 1/3과는 약간 차이가 있다.

 

이후 num = (1 / 3) * 10^20을 계산하면 실제로 연산된 값은 정확히 0.3333333333333333 * 10^N이 아닌 근사값이다.  num은 근사값인 33333333333333333120.0과 같은 값이 될 수 있다. 정밀도 제한에 의해 소수점 이하 숫자가 약간 달라질 수 있다.

때문에 int(num)을 계산하고 digit = int(num) % 10을 하면, 예상한 결과와 차이가 있을 수 있다.

 


 

이를 해결하기 위해 정수 연산으로 변경하였다.

num = A * (10 ** N) // B
digit = num % 10

 

10의 N제곱 만큼을 A에 곱해준 다음 정수 B로 나누어주었다. 그리고 N번째 자리를 추출했다.

이렇게하면 소수점 N자리까지 계산하는 효과가 있지만 부동소수점 연산을 사용하지 않는다.

 


 

decimal 모듈을 사용하는 방법도 있다.

from decimal import Decimal, getcontext

A = 1
B = 3
N = 20

getcontext().prec = N + 10  # 연산 정밀도 설정
num = Decimal(A) / Decimal(B) * (10 ** N)
digit = int(num) % 10

print(digit)  # 정확한 N번째 자리 숫자 출력

 

getcontext().prec = N + 10에 대한 설명은 decimal 모듈에서 정밀도(precision)를 설정하는 부분이다.

이 설정은 소수점 아래 몇 자릿수까지 계산을 정확하게 할지를 결정한다.

 

일반적으로 소수점 N번째 자리 수를 정확하게 얻으려면, 소수점 N자리뿐만 아니라 정수 부분까지 포함한 연산을 충분히 정확하게 처리해야한다. 이때 N + 10은, 소수점 N자리 이상을 계산할 때 약간의 오차를 방지하고 계산 과정에서 발생할 수 있는 추가적인 오차를 피하기 위해 여유를 두는 방법이다. (N + 10은 일반적인 사용 예시)

 

⭐️ 중요 포인트

소수점 자리 추출 방법은 크게 두 가지로 나눌 수 있다.

  1. 정수 연산을 이용한 방식:
    • A * (10 ** N) // B로 A를 N번 10배 확장한 후, B로 나누어 계산한다. 
  2. decimal 모듈을 이용한 방식:
    • getcontext().prec로 계산의 정밀도를 설정하고, 그 후에 계산한다.

 

부동소수점 오차를 완전히 피하려면 정수 연산이나 decimal 모듈을 사용하는 것이 좋다.

이런 방법들을 사용하면 정확한 값을 유지할 수 있다.