Processing math: 100%
 

나눗셈 실수오차가 생긴다면 직접 나눗셈을 구현하기

1206번: 사람의 수 (acmicpc.net)

 

 

n명의 사람이 0점부터 10점까지 정수로 존재하는 설문조사 문항에 점수를 내서 각 문항마다 평균을 낸 점수가

 

실수로 주어질때, n이 될 수 있는 가장 작은 정수를 구하는 문제

 

평균이 소수점 셋째자리까지만 주어진다

 

예를 들어 32/106 = 0.3018867924528302... 인데 0.301만 주어지는

 

----------------------------------------------------------------------------------------------------------------------------------

 

만약 설문조사한 사람 수가 x명이고 i번째 문항의 점수 합이 v이면

 

vxA[i]

 

A[i]가 소수점 넷째자리에서 버려져있으므로

 

A[i]<=vx<A[i]+0.001

 

그러므로 A[i]x<=v<A[i]x+0.001x

 

이 범위를 만족하는 정수 v가 있다면 그러한 정수 v는 i번째 문항의 점수 합이 될 수 있다

 

여기서 x는 1부터 1000명까지만 가능하다

 

왜냐하면 소수점 셋째자리까지만 주어지기 때문에 x = 1000이면 점수 합이 무조건 정수이므로 1000명이면 반드시 조건을 만족한다

 

이제 x = 1부터 1000까지에 대하여 가능한 정수 v로부터 v/x가 A[i]와 같은지 조사하면 된다

 

그런데 A[i]는 소수점 셋째자리까지만 나와있고 v/x를 하면 그 이상이 나오니까.. 소수점 셋째자리까지만 적당히 비교하면

 

될 수 있겠지만 부동소수점 오차때문인지 그렇게 하면 틀리는

 

그래서 v/x를 정확하게 소수점 셋째자리까지만 구한다

 

실제 나눗셈 하는 방법대로.. 아래 그림을 직접 구현하는 것이다

 

etc-image-0

 

 

 

#a/b를 소수점 셋째자리까지만 정확하게 구하는 나눗셈
def divide(a,b):
    
    answer = []

    p,r = a//b, a%b

    answer.append(str(p))
    answer.append('.')

    a = r*10

    while len(answer) < 5:

        p,r = a//b, a%b
        answer.append(str(p))
        a = r*10
    
    return float(''.join(answer))

 

 

근데 문제는 v를 찾는데 실수오차로 자꾸 틀린다는거

 

x = 1,2,3,...,1000이고 A[i]가 실수인데 하한 A[i] * x로 실수와 정수의 곱으로 실수이고

 

A[i]*x + 0.001 * x가 v의 상한인데 A[i] * x + 0.001*x로 실수의 합을 구해보면...

 

etc-image-1

 

 

위와 같이 예상하지 못한 값이 나올 수가 있음

 

예를 들어 131.0이어야하는데 130.9999999999991 이렇게 나올수도 있다는거지

 

그래서 그냥 Decimal로 해결하는게 마음 편하다

 

from sys import stdin
from decimal import Decimal

def divide(a,b):
    
    answer = []

    p,r = a//b, a%b

    answer.append(str(p))
    answer.append('.')

    a = r*10

    while len(answer) < 5:

        p,r = a//b, a%b
        answer.append(str(p))
        a = r*10
    
    return float(''.join(answer))

n = int(stdin.readline())

A = []

for _ in range(n):
    
    s = Decimal(stdin.readline())
    A.append(s)

x = 1

for x in range(1,1001):
    
    no = False

    for i in range(n):
        
        v1 = A[i]*Decimal(x)
        v2 = (A[i] + Decimal('0.001'))*Decimal(x)
        
        if int(v1) == v1:
            
            v1 = int(v1)
        
        else:
            
            v1 = int(v1) + 1
        
        if v1 < v2:

            d = divide(v1,x)
            
            if d != float(A[i]):

                no = True
                break
        
        else:
            
            no = True
            break
    
    if no == False:
        
        break

print(x)

 

 

아니면 생각하기 싫다면 그냥 v = A[i]*x해놓고 int(v), int(v)+1 두가지 조사해보는것도 AC받기는 하는데

 

흠 뭔가 좀 아쉬워

 

n = int(stdin.readline())

A = []

for _ in range(n):
    
    s = float(stdin.readline())
    A.append(s)

x = 1

for x in range(1,1001):
    
    no = False

    for i in range(n):
        
        v = A[i]*x

        v1 = divide(int(v),x)
        v2 = divide(int(v)+1,x)

        if v1 != A[i] and v2 != A[i]:

            no = True
            break
    
    if no == False:
        
        break

print(x)
728x90