팩토리얼 로직 또 수정

이건 또 언제 떠올랐느냐…

편의점에서 점심 사서 계산할 때 어 근데 유리수 어캄? 하면서 떠올랐습니다…

농담 아님.


팩토리얼은 어디까지 되는가

팩토리얼 로직에 뭐 음수도 안되고 뭣도 안되고 뭐 많았는데… 결론부터 말하자면 우리가 고등학생때 배운 팩토리얼을 정의할 수 있는 건 자연수뿐이다. 그러니까 정수 말고 0 말고 1부터 시작해서 자연수. 음수는 팩토리얼이 정의가 안 되고 0!은 걍 1이고 정수가 아닌 유리수(그러니까 q/p꼴인 수 중 p가 1이 아닌 수)는 감마 함수에 때려박아야 팩토리얼이 나온다.

그리고 이게 문제의 감마 함수.

저기다가는 뭐 1 2 이런거 때려박아도 되고(감마(n)=(n-1)!) 1.5 2.5 이런거 때려박아도 되고 복소수를 때려박아도 되고 다 된다. 근데 저기서도 음수는 안된다. 정수가 아닌 유리수인데 0보다 작거나, 복소수인데 실수부가 음수면 감마함수가 아니라 감마함수 할아버지가 와도 안된다. 물론 오일러가 살아돌아와도 안된다

그래서 뭐때문에 수정했냐고? 아니 정수가 아닌 유리수 처리한다고 수정했다니까요. 저걸 어떻게 코딩할거임?

For문

import sys
a = float(sys.stdin.readline())
# Factorial(계승): 일반적으로 n! = 1*2*3*...*n-1*n이다. (5!=1*2*3*4*5)
factorial = 1
if a < 0:
    print("Can't calculate factorial")
    # 음수는 factorlal이 없음
elif a == 0:
    print(factorial)
    # 0! = 1
elif a % 1 != 0:
    print("정수가 아닌 유리수는 일반적인 방법으로 팩토리얼을 구할 수 없습니다. ")
else:
    for i in range(int(a),0,-1):
        factorial *= i
    print(factorial)

기본적인 로직은 비슷하고 정수가 아닌 유리수에 대한 로직만 추가되었다. 그리고 입력이 float이기 때문에 range를 잡을 때 int로 형변환을 따로 해줬다. 저렇게 안 하면 for ~ in range()는 에러뜬다. 어떻게 아느냐면 직접 봤습니다… 

정수가 아닌 유리수를 구분하는 로직도 밥 먹다 생각난건데, 소수(0.1 0.5 이런거)는 어쨌든 자릿수가 1보다 작으니까 1로 나누면 나머지가 될 거 아녀. 그럼 1로 나눴을 때 나머지가 있으면 정수가 아닌 유리수네? 해서 저렇게 된 거. 정수가 아닌 유리수여도 0보다 작으면 첫번째 if에서 거른다. 

While문

import sys
a = float(sys.stdin.readline())
# 와 팩토리얼이 생각보다 빡센거였구나... 
# Factorial(계승): 일반적으로 n! = 1*2*3*...*n-1*n이다. (5!=1*2*3*4*5)
factorial = 1
if a < 0: 
    print("Can't calculate factorial")
    # 음수는 factorial이 없음
elif a == 0: 
    factorial = 1
    # 0! = 1
elif a % 1 != 0:
    print("정수가 아닌 유리수는 일반적인 방법으로 팩토리얼을 구할 수 없습니다. ")
else: 
    while a >= 1:
        factorial *= a
        a -= 1
    print(factorial)

얘도 For문이랑 로직은 비슷한데, While은 아예 맥락이 다른 반복문이라 로직 자체가 a가 1보다 작거나 같을때까지 factorial(위에 보면 1로 선언된 변수)에 a를 곱하고 a를 하나 빼는 뺑뺑이를 돈다. 그래서 for처럼 따로 형변환을 할 필요는 없다. 

대신 출력 결과 뒤에 소수점이 하나 붙어서 나오니까 그거 뵈기 싫으면 print할 때 int로 형변환 해야 한다. 

함수 이식판

def factorial(a):
    factorial = 1
    if a < 0:
        return False
    elif a == 0:
        factorial = 1
        return factorial
    elif a % 1 != 0:
        return False
    else:
        for i in range(int(a),0,-1):
            factorial *= i
        return factorial
# Factorial 구하는 로직(...)

어째서인지는 모르겠으나 클래스/함수에는 print 대신 return이 국룰이다. print는 화면에 출력하라는 얘기고 return은 함수 다 돌리고 반환하라는 얘기. 가끔 함수 다 짰는데 리턴 까먹어서 코드 이상하게 돌아가는 경우 있다

제한효소 코드에 클래스 정의한것도 print 아니고 return으로 들어간다. 덕분에 걍 쌩으로 코드 짜는것보단 편해졌지만… (print로 일일이 출력 안 해도 되고 return False로 퉁치면 장땡임)

해당 함수는 순열/조합/계승소수 코드에 들어가 있다.