We will develop a system that performs arithmetic operations on complex numbers
as a simple but unrealistic example of a program that uses generic operations.
We begin by discussing two plausible representations for complex numbers as
ordered pairs: rectangular form (real part and imaginary part) and polar form
(magnitude and angle).
Section 2.4.2 will show how both representations can be made to coexist in a
single system through the use of type tags and generic operations.
我们将开发一个对复数执行算术运算的系统,以此作为一个使用通用操作的程序的简单(但不切实际)示例。首先讨论将复数表示为有序序对的两种合理方案:直角坐标形式(实部与虚部)和极坐标形式(模与辐角)。2.4.2 节将说明如何借助类型标签和通用操作,使两种表示在同一个系统中共存。
Like rational numbers, complex numbers are naturally represented as ordered
pairs. The set of complex numbers can be thought of as a two-dimensional space
with two orthogonal axes, the “real” axis and the “imaginary” axis. (See
Figure 2.20.) From this point of view, the complex number
z
=
x
+
i
y (where i
与有理数类似,复数天然地以有序序对来表示。复数集合可以看作一个二维空间,具有两条互相垂直的坐标轴——“实”轴与“虚”轴(见图 2.20)。从这一视角看,复数 z = x + iy(其中 i
2
=
−1) can be thought of as the point in the plane
whose real coordinate is x and whose imaginary coordinate is y.
Addition of complex numbers reduces in this representation to addition of
coordinates:
Real-part
(
= −1)可以看作平面上实坐标为 x、虚坐标为 y 的点。在这种表示下,复数的加法化归为坐标的加法:
Real-part (
z
1
+
z
2
)
=
Real-part
(
Real-part (
z
1
)
+
Real-part
(
Real-part (
z
2
)
,
Imaginary-part
(
Imaginary-part (
z
1
+
z
2
)
=
Imaginary-part
(
Imaginary-part (
z
1
)
+
Imaginary-part
(
Imaginary-part (
z
2
)
.
Figure 2.20: Complex numbers as points in the plane.
)
.
图 2.20:平面上的复数点。
When multiplying complex numbers, it is more natural to think in terms of
representing a complex number in polar form, as a magnitude and an angle (r
and A in Figure 2.20). The product of two complex numbers is the
vector obtained by stretching one complex number by the length of the other and
then rotating it through the angle of the other:
Magnitude
(
在进行复数乘法时,用极坐标形式表示复数更为自然——即用模和辐角表示(图 2.20 中的 r 和 A)。两个复数的乘积是这样一个向量:将其中一个复数按另一个复数的模拉伸,再旋转另一个复数的辐角所得到:
Magnitude (
z
1
⋅
z
2
)
=
Magnitude
(
z
1
)
⋅
Magnitude
(
z
2
)
,
Angle
(
z
1
⋅
z
2
)
=
Angle
(
z
1
)
+
Angle
(
z
2
)
.
Thus, there are two different representations for complex numbers, which are
appropriate for different operations. Yet, from the viewpoint of someone
writing a program that uses complex numbers, the principle of data abstraction
suggests that all the operations for manipulating complex numbers should be
available regardless of which representation is used by the computer. For
example, it is often useful to be able to find the magnitude of a complex
number that is specified by rectangular coordinates. Similarly, it is often
useful to be able to determine the real part of a complex number that is
specified by polar coordinates.
由此,复数有两种不同的表示方式,各自适用于不同的运算。然而,从编写使用复数程序的人的角度来看,数据抽象原则要求:无论计算机内部采用哪种表示方式,所有操作复数的运算都应当可以使用。例如,当一个复数以直角坐标形式给出时,能够求出它的模 (magnitude) 往往很有用;同样,当一个复数以极坐标形式给出时,能够求出它的实部也常常是必要的。
To design such a system, we can follow the same data-abstraction strategy we
followed in designing the rational-number package in 2.1.1.
Assume that the operations on complex numbers are implemented in terms of four
selectors: real-part, imag-part, magnitude, and
angle. Also assume that we have two procedures for constructing complex
numbers: make-from-real-imag returns a complex number with specified
real and imaginary parts, and make-from-mag-ang returns a complex number
with specified magnitude and angle. These procedures have the property that,
for any complex number z, both
为了设计这样一个系统,我们可以沿用 2.1.1 节设计有理数程序包时所采取的数据抽象策略。假设对复数的操作是通过四个选择函数来实现的:real-part、imag-part、magnitude 和 angle。同时假设我们有两个用于构造复数的过程:make-from-real-imag 返回一个具有指定实部和虚部的复数,make-from-mag-ang 返回一个具有指定模和辐角的复数。这些过程具有如下性质:对任意复数 z,以下两式
and
以及
produce complex numbers that are equal to z.
都能产生与 z 相等的复数。
Using these constructors and selectors, we can implement arithmetic on complex
numbers using the “abstract data” specified by the constructors and
selectors, just as we did for rational numbers in 2.1.1. As
shown in the formulas above, we can add and subtract complex numbers in terms
of real and imaginary parts while multiplying and dividing complex numbers in
terms of magnitudes and angles:
利用这些构造函数和选择函数,我们可以依据构造函数与选择函数所规定的"抽象数据"来实现复数的算术运算,正如我们在 2.1.1 节对有理数所做的那样。如上面的公式所示,复数的加法和减法可以用实部和虚部来表达,而复数的乘法和除法则用模和辐角来表达:
To complete the complex-number package, we must choose a representation and we
must implement the constructors and selectors in terms of primitive numbers and
primitive list structure. There are two obvious ways to do this: We can
represent a complex number in “rectangular form” as a pair (real part,
imaginary part) or in “polar form” as a pair (magnitude, angle). Which shall
we choose?
为了完成复数程序包,我们必须选择一种表示方式,并用基本数和基本表结构来实现构造函数和选择函数。显然有两种方法可以做到这一点:我们可以将复数表示为"直角形式"——一个序对(实部,虚部),或表示为"极坐标形式"——一个序对(模,辐角)。我们应当选哪种?
In order to make the different choices concrete, imagine that there are two
programmers, Ben Bitdiddle and Alyssa P. Hacker, who are independently
designing representations for the complex-number system. Ben chooses to
represent complex numbers in rectangular form. With this choice, selecting the
real and imaginary parts of a complex number is straightforward, as is
constructing a complex number with given real and imaginary parts. To find the
magnitude and the angle, or to construct a complex number with a given
magnitude and angle, he uses the trigonometric relations
为了使不同的选择更加具体,设想有两位程序员——Ben Bitdiddle 和 Alyssa P. Hacker——正在各自独立地为复数系统设计表示方式。Ben 选择用直角形式表示复数。有了这个选择,从复数中取出实部和虚部是直截了当的,用给定的实部和虚部构造复数也是如此。而要求模和辐角,或者用给定的模和辐角构造复数,他则借助三角关系式
which relate the real and imaginary parts (
x
,
y
) to the magnitude and
the angle (
r
,
A
). Ben’s
representation is therefore given by the following selectors and constructors:
这些关系式将实部和虚部(
x
,
y
)与模和辐角(
r
,
A
)联系起来。因此,Ben 的表示方式由以下选择函数和构造函数给出:
Alyssa, in contrast, chooses to represent complex numbers in polar form. For
her, selecting the magnitude and angle is straightforward, but she has to use
the trigonometric relations to obtain the real and imaginary parts. Alyssa’s
representation is:
Alyssa 则选择用极坐标形式表示复数。对她而言,取出模和辐角是直截了当的,但她必须借助三角关系式来求实部和虚部。Alyssa 的表示方式如下:
The discipline of data abstraction ensures that the same implementation of
add-complex, sub-complex, mul-complex, and
div-complex will work with either Ben’s representation or Alyssa’s
representation.
数据抽象原则保证了 add-complex、sub-complex、mul-complex 和 div-complex 的同一套实现,可以在 Ben 的表示方式或 Alyssa 的表示方式下正常工作。
(make-from-real-imag (real-part z)
(imag-part z)) (make-from-mag-ang (magnitude z)
(angle z)) (define (add-complex z1 z2)
(make-from-real-imag
(+ (real-part z1) (real-part z2))
(+ (imag-part z1) (imag-part z2))))
(define (sub-complex z1 z2)
(make-from-real-imag
(- (real-part z1) (real-part z2))
(- (imag-part z1) (imag-part z2))))
(define (mul-complex z1 z2)
(make-from-mag-ang
(* (magnitude z1) (magnitude z2))
(+ (angle z1) (angle z2))))
(define (div-complex z1 z2)
(make-from-mag-ang
(/ (magnitude z1) (magnitude z2))
(- (angle z1) (angle z2)))) (define (real-part z) (car z))
(define (imag-part z) (cdr z))
(define (magnitude z)
(sqrt (+ (square (real-part z))
(square (imag-part z)))))
(define (angle z)
(atan (imag-part z) (real-part z)))
(define (make-from-real-imag x y)
(cons x y))
(define (make-from-mag-ang r a)
(cons (* r (cos a)) (* r (sin a)))) (define (real-part z)
(* (magnitude z) (cos (angle z))))
(define (imag-part z)
(* (magnitude z) (sin (angle z))))
(define (magnitude z) (car z))
(define (angle z) (cdr z))
(define (make-from-real-imag x y)
(cons (sqrt (+ (square x) (square y)))
(atan y x)))
(define (make-from-mag-ang r a)
(cons r a))