백준 15829 math.pow 와 ** 차이

이라운·2022년 8월 23일
0

❓math.pow 를 쓰면 50점, **를 쓰면 100점??

이번 백준문제를 풀면서 이상한 현상을 발견했다.
바로 math.pow 를 쓰면 50점 밖에 못받고 ** 로 계산하면 100점이 나오는 것이다.


💻 코드

import math
import sys
input = sys.stdin.readline

N = int(input())
str = list(input())
nums = [ord(x) - 96 for x in str]

ans = 0
for i in range(N):
    ans += nums[i] * 31 ** i % 1234567891
    # 아래처럼 계산 방법이 바뀌면 바로 50점만 받는다.
    # ans += nums[i] * math.pow(31, i) % 1234567891

print(ans % 1234567891)

이렇게 숫자의 범위가 크고 작음을 기준으로 점수를 주는데, math.pow 로 계산하면 값이 나오지 않는다. 그래서 또 열심히 구글링을 해보다가 가닥을 잡을 수 있는 포스팅을 발견했다.


💡IEEE754

파이썬에서의 pow 와 math.pow 차이점
파이썬의 math.pow 는 IEEE754 방법을 사용하고 float 타입에서 overflow 가 발생한다는 것이다.
그래서 진짜로 python 이 IEEE754 를 사용하는지 알아봤다.
파이썬 공식문서 - 부동소수점: 이슈와 한계점

실제로 파이썬의 float 은 IEEE754의 double precision 으로 매핑되어 있고 이는 유효자리수가 2진수 53이라는 것이다.
math.pow 를 쓰면 float 타입으로 계산이 되는데, 그 과정에서 표현할 수 있는 precision 이상으로 overflow 가 되면서 답을 내지 못하는 것이다.

근데 또 여기서 double precision... 53자리... 이런게 또 무슨 말인가 싶어서 한국어자료를 찾아봤다.

KOCW 에서 충북대학교의 이건명 교수님의 기초컴퓨터프로그래밍 강좌 자료에서 찾을 수 있었다.

가수 부분을 보면 52비트 자리까지 가능하지만, 의미적으로 부호를 표현하는 1bit 가 있으므로 53비트의 표현효과를 가진다고 말하는 것이었다.

차재복 개인연구실에서 운영한다고 밝히고 있는 정보통신기술용어해설 에서 본 결과

10진수 유효자리수는 2의 53제곱은 10의 15.95제곱이므로 십진수로 약 16자리까지의 표현효과를 가진다고 말한다.


✅ 결론

즉, math.pow 는 IEEE754라는 부동소수점 표현 방법으로 매핑되어 있다보니 숫자가 커지면 overflow 가 발생하면서 답이 나오지 않는다는 것이다.

휴우... 아직 제대로 IEEE754 를 이해하진 못했는데, 그래도 이젠 뭔가 마음이 편안해졌다. 이유를 찾은 느낌?

profile
Programmer + Poet = Proet

0개의 댓글