openlang

round(2.5)가 2라는 걸 학습자들은 안 믿는다

학습자들은 자꾸 round(2.5)가 3일 거라고 짐작하는데, 제가 주로 쓰는 두 언어는 다 2라고 해요. Python은 정수 2를, Julia는 2.0을 줘요. 둘 다 동점을 짝수 쪽 이웃으로 보내서 round(0.5)는 0, round(1.5)는 2가 되는데, 이 패턴은 동점 몇 개를 나란히 놓아야 보여요.

print([round(x) for x in (0.5, 1.5, 2.5, 3.5)])

출력은 [0, 2, 2, 4]이고, Julia도 같은 값을 실수로 줘요. 제 짐작으로는 규칙을 말해 주는 것보다 동점 네 개를 한꺼번에 보여 주는 게 더 잘 가르쳐져요. 2 옆에 또 2가 있는 게 고장 난 것처럼 보이고, 그다음엔 질문이 누가 이걸 원하느냐로 바뀌거든요.

계속 고민되는 건 첫 예제에 음수 동점까지 넣을지예요. 부호까지 끼어드는 경우인데, 그게 도움이 될지 잡음만 늘릴지 모르겠어요.

이어지는 대화 4

서로의 근거를 따라
  1. 고유 링크

    왜냐는 질문의 답은 셈이에요. 동점 네 개를 그대로 더하면 8이에요. 먼저 반올림을 위쪽으로 하면 1 + 2 + 3 + 4 = 10이에요. 짝수 쪽으로 하면 0 + 2 + 2 + 4 = 8이에요. 위쪽 반올림은 모든 동점을 같은 방향으로 밀어서 동점이 많을수록 오차가 커져요. 짝수 쪽은 절반씩 양쪽으로 보내니까 평균적으로 상쇄돼요. 언어를 오가는 학습자는 둘 다 만나요. Go의 math.Round는 0에서 먼 쪽으로 반올림하고, math.RoundToEven은 별도 함수거든요.

  2. 고유 링크

    이 수업과는 따로 떼어 두면 좋을 게 하나 있는 것 같아요. Python에서 round(2.675, 2)는 2.67을 주는데, 학습자들은 이걸 같은 놀라움으로 분류하지만 원인이 달라요. 2.675에 가장 가까운 부동소수점 값이 그보다 살짝 작아서 깨뜨릴 동점이 아예 없거든요. Python 문서도 바로 이 예를 들어요. 그래서 먼저 0.5나 2.5처럼 이진수로 정확한 값으로 동점을 다루고, 표현 문제는 두 번째 단계로 넘겨요.

    from decimal import Decimal, ROUND_HALF_UP
    print(Decimal(2.675))
    print(Decimal('2.675').quantize(Decimal('0.01'), rounding=ROUND_HALF_UP))

    첫 줄은 저장된 값 2.67499999999999982236431605997495353221893310546875를 보여 줘요. 둘째 줄은 2.68을 줘요. 문자열은 학습자가 실제로 입력한 십진수 값을 그대로 지니고 있으니까요.

  3. 고유 링크

    Python의 round(-0.5)는 정수 0을 주고, round(-0.5, 0)과 Julia의 round(-0.5)는 -0.0을 줘요. Julia가 그걸로 나눠서 -Inf를 돌려주기 전까지는 아무도 몰라요.

같은 질문의 다른 갈래

  1. 3 + 4 * 2가 14라는 건 쉬운 쪽이다

    Smalltalk을 처음 배우는 사람은 누구나 일찍 3 + 4 * 2를 만나고 그게 14라는 말을 들어요. 이항 메시지는 산술 우선순위 없이 왼쪽에서 오른쪽으로 가니까요. 이 부분은 한 번 보여 주면 기억에 남아요(정말 그냥…

  2. 옛 CoffeeScript를 손으로 옮기는 JavaScript 연습

    유행은 지났지만 생각보다 훨씬 잘 먹히는 연습이 있습니다. 배우는 사람에게 작고 오래된 CoffeeScript 파일을 하나 주고, 컴파일러를 돌리지 말고 현대 JavaScript로 다시 쓰게 하는 것입니다. 거의 모든 설탕…

  3. (x, x)는 두 값이 같다는 뜻이 아니다

    OCaml의 (x, x)를 "두 값이 같다"로 읽는 학습자가 계속 나와요. 그런 뜻도 아니고, 애초에 허용되지도 않아요. 처음 배우는 사람은 대개 두 설명 중 하나를 떠올려요. 하나는 앞의 x가 구성 요소에 이름을 붙이고 뒤…

    답글 5ocaml