(Lispex)sicp.io
2.11 · 복소수의 여러 표현

복소수 하나는 서로 유용한 두 좌표계를 가질 수 있다.

직교형 내용은 덧셈을 직접적으로 만들고 극형 내용은 곱셈을 직접적으로 만듭니다. 하나의 태그 선택자 인터페이스는 어느 표현이든 같은 추상 복소수로 관찰하게 합니다.

생각해 볼 질문

복소수 인터페이스 하나가 직교형과 극형 표현의 장점을 동시에 보존하려면 어떻게 해야 할까요?

  • 실수부와 허수부로 직교형 내용 만들기
  • 크기와 각도로 극형 내용 만들기
  • 표현 태그를 통해 공통 선택자 디스패치하기
  • 덧셈에는 직교 좌표를, 곱셈에는 극 좌표를 사용하기
  • 부동소수점 삼각함수 관찰을 명시적인 허용 오차로 비교하기

직교형 객체는 x와 y를 저장하므로 real-part와 imag-part는 바로 읽고 크기와 각도는 계산합니다. 극형 객체는 r과 a를 저장하므로 크기와 각도는 바로 읽고 실수부와 허수부는 계산합니다. 바깥 태그는 표현에 대한 정보이며 클라이언트 코드가 보는 추상 복소수의 일부는 아닙니다.

첫 프로그램은 3 + 4i를 두 표현으로 각각 만들고 같은 네 선택자로 관찰합니다. close?는 삼각함수를 거친 부동소수점 값이 선언한 허용 오차 안에서 일치한다는 사실을 기록합니다. 두 번째 프로그램은 실수부와 허수부를 더해 직교형 결과를 만들고, 크기를 곱하고 각도를 더해 극형 결과를 만듭니다. 공통 선택자는 어느 결과에서도 내부 내용을 노출하지 않고 추상적인 값을 확인합니다.

리스펙스 · SICP 코드SICP에 필요한 Scheme 호환 문법을 리스펙스 SICP 프로필로 실행합니다.
(begin
  (define (square x) (* x x))
  (define (close? left right)
    (< (abs (- left right)) 0.000001))
  (define (attach-tag type contents) (cons type contents))
  (define (type-tag object) (car object))
  (define (contents object) (cdr object))
  (define (make-from-real-imag x y)
    (attach-tag 'rectangular (list x y)))
  (define (make-from-mag-ang magnitude angle)
    (attach-tag 'polar (list magnitude angle)))
  (define (rectangular-real z) (car z))
  (define (rectangular-imag z) (cadr z))
  (define (rectangular-magnitude z)
    (sqrt (+ (square (rectangular-real z))
             (square (rectangular-imag z)))))
  (define (rectangular-angle z)
    (atan (rectangular-imag z) (rectangular-real z)))
  (define (polar-magnitude z) (car z))
  (define (polar-angle z) (cadr z))
  (define (polar-real z)
    (* (polar-magnitude z) (cos (polar-angle z))))
  (define (polar-imag z)
    (* (polar-magnitude z) (sin (polar-angle z))))
  (define (select object rectangular-selector polar-selector)
    (cond ((eq? (type-tag object) 'rectangular)
           (rectangular-selector (contents object)))
          ((eq? (type-tag object) 'polar)
           (polar-selector (contents object)))
          (else (error "unknown complex representation"))))
  (define (real-part z) (select z rectangular-real polar-real))
  (define (imag-part z) (select z rectangular-imag polar-imag))
  (define (magnitude z)
    (select z rectangular-magnitude polar-magnitude))
  (define (angle z) (select z rectangular-angle polar-angle))
  (define rectangular (make-from-real-imag 3.0 4.0))
  (define polar (make-from-mag-ang 5.0 (atan 4.0 3.0)))
  (list (type-tag rectangular)
        (type-tag polar)
        (close? (real-part rectangular) (real-part polar))
        (close? (imag-part rectangular) (imag-part polar))
        (close? (magnitude rectangular) (magnitude polar))
        (close? (angle rectangular) (angle polar))))
리스펙스 학습용 런타임리스펙스 SICP 프로필 1.0.0
리스펙스 SICP 런타임 불러오는 중
리스펙스 · SICP 코드UTF-8 1,914 / 1,048,576바이트
예제
결과
출력
진단
보이는 실행 흐름0 / 0 개의 실행 이벤트
    이 브라우저 결과는 리스펙스 바우치나 권한이 아닙니다.wasm —
    예상 관찰

    첫 프로그램은 (rectangular polar #t #t #t #t)를 반환합니다. 두 번째 프로그램은 (rectangular polar #t #t #t #t #t #t)를 반환합니다.

    실행 흐름에서 볼 점

    각 선택자가 직교형 또는 극형 내용을 고르기 전에 바깥 type tag를 읽는 과정을 따라가세요. 첫 실행에서는 직접 읽는 선택자와 sqrt, atan, sin, cos를 거치는 경로를 비교합니다. 두 번째 실행에서는 덧셈이 직교형 내용을 만들고 곱셈이 극형 내용을 만든 뒤 같은 공통 선택자가 두 결과를 확인하는지 보세요. 허용 오차는 이번 유한한 부동소수점 계산만 설명하며 임의의 수치 프로그램에 대한 동등성 증명은 아닙니다.

    직접 해보기

    힌트를 보기 전에 프로그램을 바꿔 보세요.

    -3 + 4i를 크기 5와 각도 (atan 4.0 -3.0)을 사용해 두 표현으로 각각 만드세요. close?로 네 선택자를 확인한 뒤 첫 사분면 밖에서 atan의 두 인자가 필요한 이유를 설명하세요.

    힌트 하나 보기

    두 좌표의 부호가 사분면을 결정합니다. y를 x로 나눈 값에 한 인자 atan만 적용하면 그 구분을 잃습니다.