본문 바로가기

프로그래밍/Python

파이썬 지수 수치계산방식에 따른 차이

반응형

"""
    calculate
                        50000
    /       n         \
    |    10    - 1     |
    |   ------------   |
    |          n       |
    \       10        /
"""
import math

def f(n):
    return ((10 ** n - 1) / (10 ** n)) ** 50000

def f2(n):
    return (1 - 10 ** (-n)) ** 50000

def f_exp10_log10(n):
    exponent = 50000 * (math.log10(10 ** n - 1) - n)
    return 10 ** exponent

def f_exp2_log2(n):
    exponent = 50000 * (math.log2(10 ** n - 1) - n * math.log2(10))
    return 2 ** exponent

def f_exp_ln(n):
    exponent = 50000 * (math.log(10 ** n - 1) - n * math.log(10))
    return math.e ** exponent

for n in range(1, 20):
    r = f(n), f2(n), f_exp10_log10(n), f_exp2_log2(n), f_exp_ln(n)
    print(n, r)

1에 가깝지만, 1보다 작은 수를 여러번 거듭제곱한 결과를 계산하는 코드입니다. 수치계산에는 오차가 있기 때문에, 여러 방법으로 구현을 해 보고 결과를 봤습니다.

1 (0.0, 0.0, 0.0, 0.0, 0.0)
2 (5.750821364590612e-219, 5.750821364590612e-219, 5.750821364582722e-219, 5.750821364628167e-219, 5.750821364428947e-219)
3 (1.8810974691235773e-22, 1.8810974691235773e-22, 1.8810974691317268e-22, 1.8810974691862467e-22, 1.8810974690998245e-22)
4 (0.006736262610603238, 0.006736262610603238, 0.006736262610461906, 0.006736262610695879, 0.006736262610337693)
5 (0.6065291433791509, 0.6065291433791509, 0.6065291433740616, 0.6065291433487209, 0.6065291433184291)
6 (0.9512294007185952, 0.9512294007185952, 0.9512294007397432, 0.951229400728889, 0.9512294006267303)
7 (0.9950124789465479, 0.9950124789465479, 0.99501247895579, 0.9950124789848356, 0.9950124789577935)
8 (0.9995001249741594, 0.9995001249741594, 0.9995001249962548, 0.9995001250444372, 0.9995001249378198)
9 (0.9999500012513682, 0.9999500012513682, 0.9999500012619135, 0.9999500013180697, 0.9999500010682155)
10 (0.9999950000120861, 0.9999950000120861, 0.9999949999318897, 0.9999950000439347, 0.9999949997456341)
11 (0.9999995000000836, 0.9999995000000836, 0.9999994999716129, 0.9999995001017706, 0.9999994999556747)
12 (0.9999999500011073, 0.9999999500011073, 0.9999999500994053, 0.9999999500101658, 0.9999999499067384)
13 (0.9999999949984453, 0.9999999949984453, 0.9999999950917446, 0.9999999950748931, 0.9999999948485652)
14 (0.9999999995003996, 0.9999999995003996, 0.9999999995909787, 0.9999999995074893, 0.9999999992894573)
15 (0.99999999995004, 0.99999999995004, 1.0, 1.0, 0.9999999996447286)
16 (0.9999999999944489, 0.9999999999944489, 1.0, 1.0, 1.0)
17 (1.0, 1.0, 1.0, 1.0, 1.0)
18 (1.0, 1.0, 1.0, 1.0000000002462552, 0.9999999996447286)
19 (1.0, 1.0, 1.0, 1.0000000002462552, 1.0)
  1. n 이 1, 2, 3 까지는 모든 구현의 결과가 같아 보이고,
  2. n 이 15일 때, 1이라는 결과 (수학적으로는 도달하지 않는 결과)가 몇 개 구현에서 나옵니다.
  3. 실험해 보기 전에는 거의 브루트포스로 구현한 f, f2 가 덜 정확할거라고 생각했는데, 약간 테크닉을 써서 로그, 지수 함수를 사용해서 구현한 것이 오히려 덜 정확하네요. 왜그럴까요?
  4. 그리고, 18, 19에서 절대 나와서는 안 되는 1보다 큰 결과가 나오네요. 이건.. 정말 예상 못한 결과네요. 버그가 뭘까요?
728x90