Python-Collatz 시퀀스
On 12월 1, 2020 by admin장에서 Collatz 시퀀스에 대한 내 코드를 검토 할 수 있습니까? Python으로 지루한 작업 자동화 중 3 개?
The Collatz 시퀀스
number라는 매개 변수가 하나있는 collatz ()라는 함수를 작성하십시오. 숫자가 짝수이면 collatz ()는 숫자 // 2를 인쇄하고이 값을 반환해야합니다. 숫자가 홀수이면 collatz ()는 3 * 숫자 + 1을 출력하고 반환해야합니다.
그런 다음 사용자가 정수를 입력 할 수 있도록하고 해당 숫자에 대해 collatz ()를 계속 호출하는 프로그램을 작성합니다. 함수는 값 1을 반환합니다. (놀랍게도이 시퀀스는 실제로 모든 정수에 대해 작동합니다. 조만간이 시퀀스를 사용하면 1에 도달 할 것입니다! 심지어 수학자들도 이유를 모릅니다. 프로그램이 Collatz 시퀀스라고하는 것을 탐색하고 있습니다. , “가장 단순한 불가능한 수학 문제”라고도합니다.)
int () 함수를 사용하여 input ()의 반환 값을 정수로 변환하는 것을 기억하십시오. 그렇지 않으면 문자열 값이됩니다.
힌트 : 정수는 숫자 % 2 == 0이면 짝수이고 숫자 % 2 == 1이면 홀수입니다.
이 프로그램의 출력은 다음과 같습니다.
Enter number: 3 10 5 16 8 4 2 1
입력 유효성 검사
이전 프로젝트에 try 및 except 문을 추가하여 사용자가 정수가 아닌 문자열을 입력하는지 감지합니다. 일반적으로 int ( “puppy”)에서와 같이 int () 함수는 정수가 아닌 문자열이 전달되면 ValueError 오류를 발생시킵니다. except 절에서 사용자에게 정수를 입력해야한다는 메시지를 인쇄합니다.
저는 주로 내 문서를 더 깔끔하게 작성할 수있는 방법이 있는지 궁금합니다. 솔루션.
def collatz(num): while num > 1: if num % 2 == 0: print(num//2) num = num //2 elif num % 2 ==1: print(3*num+1) num = 3*num+1 else: print(num) def getNum(): global num num = (input("> ")) try: num = int(num) except ValueError: print("plese enter a number") getNum() getNum() collatz(num)
댓글
- 입력 및 출력의 예와 함께이 3 장에서 권장하는 사항을 나타내는 설명을 추가하세요. ' 누구도 이것이 무엇인지 추측하지 않습니다.
- @Edmad Broctor 및 @ Carcigenicate 피드백에 감사드립니다. 계속해서 게시물을 수정했습니다.
- " 놀랍게도이 시퀀스는 실제로 모든 정수에서 작동합니다. 조만간이 시퀀스를 사용하면 도착할 것입니다. at 1! " 사실 우리는 ' 어떤 정수에서도 작동하는지 알지 못합니다. 항상 1에 도달한다는 생각은 추측입니다. .
- @PierreCath é이 의견 상자가 너무 작아서 담을 수없는이 제안에 대한 정말 놀라운 시연이 있습니다.
- @Acccumulation 와 ! ' 인상적입니다.이 경우 Wikipedia 기사를 업데이트하고 International Mathematical Union에 연락하여 Fields Medal을 받아야합니다.
답변
먼저 계산을 어떻게 복제하는지 확인하세요.
print(num//2) num = num //2
이 특정 코드에 문제를 일으키지는 않지만 좋은 습관은 아닙니다. 더 복잡한 코드를 작성하기 시작하면 성능 문제가 발생할 수 있으므로 필요한 것보다 두 배 많은 작업을 수행하고 있습니다. 계산을 한 번 수행하고 결과를 저장합니다.이 경우에는 해당 행을 뒤집기 만하면됩니다. num
사용 :
num = num // 2 print(num)
또한 적절한 간격이 있는지 확인하십시오. 연산자를 중심으로 일관성을 유지하세요 .
if
및 elif
케이스는 서로 배타적이며 else
는 절대 발생하지 않아야합니다. 첫 번째 조건이 참이면 다른 조건은 거짓이어야하고 그 반대의 경우도 마찬가지입니다. 두 번째 확인. 다시 작성하면 모든 경우에 인쇄 할 필요가 없음을 알 수 있습니다. 다음 이후에 인쇄 할 수 있습니다.
while num > 1: if num % 2 == 0: num = num // 2 else: num = 3 * num + 1 print(num)
num
다음 두 가지 옵션 중 하나를 조건식은 여기에서도 깔끔하게 사용할 수 있습니다.
while num > 1: num = (num // 2) if num % 2 == 0 else (3 * num + 1) print(num)
중괄호는 필요하지 않지만 여기에서 유용하다고 생각합니다. 관련된 연산자의 수.
여기에서는 숫자를 인쇄하는 것이 이상적이지 않습니다. 대부분의 코드에서 생성하는 데이터를 사용 할 수 있어야합니다. 생성 된 시퀀스를 분석하려면 비용이 많이 들고 지나치게 복잡한 표준 출력을 가로채는 작업을 수행해야합니다. 목록을 누적하고 반환하는 함수로 만듭니다.다음 예에서는 데이터 유형이 무엇인지 명확히하기 위해 몇 가지 유형 힌트 를 추가했습니다.
from typing import List def collatz(starting_num: int) -> List[int]: nums = [starting_num] num = starting_num while num > 1: num = (num // 2) if num % 2 == 0 else (3 * num + 1) nums.append(num) return nums
또는 훨씬 더 깔끔한 접근 방식은 숫자를 산출하는 생성기 로 만드는 것입니다.
# Calling this function returns a generator that produces ints # Ignore the two Nones, as they aren"t needed for this kind of generator def collatz_gen(starting_num: int) -> Generator[int, None, None]: yield starting_num num = starting_num while num > 1: num = (num // 2) if num % 2 == 0 else (3 * num + 1) yield num >>> list(collatz_gen(5)) [5, 16, 8, 4, 2, 1]
“getNum
에 대해 몇 가지 주목할만한 사항이 있습니다.
Python은 “camelCase”가 아닌 “snake_case”를 사용합니다.
여기서 global num
를 사용하는 것은 불필요하고 혼란 스럽습니다. . 이전과 마찬가지로 함수가 생성하는 모든 데이터를 명시 적으로 return
:
def get_num() -> int: raw_num = input("> ") try: return int(raw_num) except ValueError: print("Please enter a number") return get_num()
글로벌 num
, 우리는 단지 숫자를 반환합니다. 나는 또한 약간의 간격을두고 좀 더 적절한 이름을 사용했습니다. 개념적으로는 num = input("> ")
가 틀렸다고 말하고 싶습니다. 실행되는 시점에 num
는 틀리지 않습니다 . 숫자를 포함합니다 (문자열 포함).
이것은 재귀를 잘 사용하지 않습니다. 가능성 은 문제를 일으키지 않지만, 사용자가 정말 멍청하고 잘못된 데이터를 최대 1000 번 입력하면 프로그램이 중단됩니다. 루프를 사용하면됩니다.
def get_num() -> int: while True: raw_num = input("> ") try: return int(raw_num) except ValueError: print("Please enter a number")
Python과 같은 언어에서는 함수가 반복되는 횟수에 대한 보장이없는 경우 재귀를 사용하는 데주의하세요.
I “d 또한 아마도 ask_for_num
에 더 가까운 이름을 지정하십시오. “get”은 데이터의 출처를 명확하게 보여주지 않습니다.
전체적으로 보면 다음과 같이됩니다.
from typing import Generator def collatz_gen(starting_num: int) -> Generator[int, None, None]: yield starting_num num = starting_num while num > 1: num = (num // 2) if num % 2 == 0 else (3 * num + 1) yield num def ask_for_num() -> int: while True: raw_num = input("> ") try: return int(raw_num) except ValueError: print("Please enter a number")
다음과 같이 사용할 수 있습니다.
num = ask_for_num() for n in collatz_gen(num): print(n)
답변
프롬프트
여기서 가장 명백한 나쁜 습관은 전역 변수를 사용하는 것입니다. num
를 부작용으로 설정하는 대신 함수는 결과를 return
해야합니다.
getNum()
는 함수의 좋은 이름이 아닙니다. Python의 공식 스타일 가이드 인 PEP 8 은 함수 이름이 lower_case_with_underscores
이어야한다고 말합니다. 또한 “get”은 함수가 이미 어딘가에 저장된 데이터 조각을 검색하고 있음을 의미하며, 여기에서는 그렇지 않습니다. 마지막으로 “Num”은 더 구체적이어야합니다.
재귀 사용은 적절하지 않습니다. 루프를 원하면 루프를 작성하세요.
def ask_integer(): """ Return an integer entered by the user (repeatedly prompting if the input is not a valid integer). """ while True: try: return int(input("> ")) except ValueError: print("Please enter an integer") num = ask_integer()
collatz
함수
엄격히 즉, “지침을 따르지 않았습니다. 귀하의 솔루션은 잘못되거나 나쁘지 않습니다. 제공된 사양에 따라 collatz
함수를 구현하지 않았습니다. 하나의 숫자를 인쇄하여 반환해야합니다.
def collatz(num): """ Given a number, print and return its successor in the Collatz sequence. """ next = num // 2 if num % 2 == 0 else 3 * num + 1 print(next) return next num = ask_integer() while num > 1: num = collatz(num)
설명
- 테스트를 반대로하고 0과의 비교 :
next = 3 * num + 1 if num % 2 else num // 2
- @RootTwo 솔직히 그게 의도를 망친다는 것을 알았습니다. 우리는 '
num % 2
가 거짓인지 확인하지 않고, ' 술어가 아닙니다. 우리는 ' '가 0과 같은지 확인합니다. ' Python에서 동일합니다. -
next = ...
는 내장 된next
. 이 맥락에서 ' 위험하지는 않지만 알아두면 좋은 것입니다. - 기술적으로는
if num % 2 else
, 여기에 의도를 표시하는 것이 더 중요하다는 데 동의합니다. 그리고if num % 2 == 0 else
는 그 의도를 더 잘 전달합니다. 하지만next
변수의 이름을 변경해야한다는 데 동의합니다. ' 나쁜 습관입니다. - @ 200_success 단순히 인쇄하는 것이 아니라 번호를 반환하지 않은 것을 지적 해 주셔서 감사합니다. 매우 도움이되었습니다.
답변
완벽 성을 위해 (이미 num
입력에 대한 좋은 제안을 충분히 받았습니다) :
def collatz(num): print(num) if num == 1: return num if num % 2 == 0: return collatz(num // 2) return collatz(3 * num + 1) collatz(3)
출력
3 10 5 16 8 4 2 1
댓글
- 없음 ' 이 답변이 OP에 도움이된다고 생각합니다. 재귀 적 정의는 확실히 가능하지만 ' 충족하려는 사양에 맞지 않습니다. 또한이 코드에는 중복성이 있습니다.이 함수는 항상 1을 반환합니다 (반환 할 때). 그러면 왜 반환 값이있는 것일까 요?
- @MeesdeVries
the function always returns 1 (when it returns at all), so why even have a return value
나는 ' 따르는 지 잘 모르겠습니다. 재귀에는 기본 케이스가 있어야합니다. 이 예의 기본 사례는num == 1
입니다. 예제 출력은 함수가 항상 1을 반환하지 않는 것을 보여줍니다. - 함수는 다른 값을 인쇄 하지만 값 1 만 반환 합니다.
- 당신의 요점이 무엇인지 잘 모르겠습니다. . 내 원래 의견은 입력에 관계없이 항상 숫자 1이기 때문에 작성한 함수가 아무것도 반환 할 필요가 없다고 언급했습니다. 따라서 더 나은 구현은 의미가 있다는 제안을 피하기 위해 값을 반환하지 않습니다. 예를 들어, (재귀 부분의) 더 나은 구현은
if num % 2 == 0: collatz(num//2); elif num > 1: collatz(3 * num + 1)
라고 말할 수 있습니다. - 내가 작성한 코드를 직접 확인해보십시오. 그렇지 않습니다 (적어도 양의 정수 입력의 경우). 이 문제에 대해 더 논의하고 싶으시면 채팅에 가져 가시기 바랍니다.
답글 남기기