gopl-zh.github.com/ch3/ch3-03.md
chai2010 6b264c03e5 ch03-3 done
Fixes #56
2015-12-18 21:11:16 +08:00

3.8 KiB
Raw Blame History

3.3. 複數

Go提供了两种精度的复数类似, complex64 和 complex128, 分别对应 float32 和 float64精度. 内置的 complex 函数用于构建复数, 内建的 real 和 imag 函数返回复数的实部和虚部:

var x complex128 = complex(1, 2) // 1+2i
var y complex128 = complex(3, 4) // 3+4i
fmt.Println(x*y)                 // "(-5+10i)"
fmt.Println(real(x*y))           // "-5"
fmt.Println(imag(x*y))           // "10"

如果一个浮点数面值或一个十进制整数面值后面跟着一个i, 例如 3.141592i 或 2i, 它将构成一个复数的虚部, 复数的实部是0:

fmt.Println(1i * 1i) // "(-1+0i)", i^2 = -1

在常量算术规则下, 一个复数常量可以加到另一个常量(整数或浮点数, 实部或虚部), 我们可以用自然的方式写复数, 就像 1+2i, 或与之等价的写法 2i+1. 上面x和y的声明语句还可以简化:

x := 1 + 2i
y := 3 + 4i

复数也可以用 == 和 != 进行相等比较. 只有两个复数的实部和虚部都相等的时候它们才是相等的.

math/cmplx 包提供了复数处理的许多函数, 例如求复数的平方根函数和求幂函数.

fmt.Println(cmplx.Sqrt(-1)) // "(0+1i)"

下面的程序使用complex128复数算法来生成一个Mandelbrot图像.

gopl.io/ch3/mandelbrot

// Mandelbrot emits a PNG image of the Mandelbrot fractal.
package main

import (
	"image"
	"image/color"
	"image/png"
	"math/cmplx"
	"os"
)


func main() {
	const (
		xmin, ymin, xmax, ymax = -2, -2, +2, +2
		width, height          = 1024, 1024
	)

	img := image.NewRGBA(image.Rect(0, 0, width, height))
	for py := 0; py < height; py++ {
		y := float64(py)/height*(ymax-ymin) + ymin
		for px := 0; px < width; px++ {
			x := float64(px)/width*(xmax-xmin) + xmin
			z := complex(x, y)
			// Image point (px, py) represents complex value z.
			img.Set(px, py, mandelbrot(z))
		}
	}
	png.Encode(os.Stdout, img) // NOTE: ignoring errors
}

func mandelbrot(z complex128) color.Color {
	const iterations = 200
	const contrast = 15

	var v complex128
	for n := uint8(0); n < iterations; n++ {
		v = v*v + z
		if cmplx.Abs(v) > 2 {
			return color.Gray{255 - contrast*n}
		}
	}
	return color.Black
}

遍历1024x1024图像每个点的两个嵌套的循环对应 -2 到 +2 区间的复数平面. 程序反复测试每个点对应复数值平方值加一个增量值对应的点是否超出半径为2的圆. 如果超过了, 通过根据逃逸的迭代次数对应的灰度颜色来代替. 如果不是, 该点属于Mandelbrot集合, 使用黑色颜色标记. 最终程序将生成的PNG格式分形图像图像输出到标准输出, 如图3.3所示.

练习3.5: 实现一个彩色的Mandelbrot图像, 使用 image.NewRGBA 创建图像, 使用 color.RGBA 或 color.YCbCr 生成颜色.

练习3.6: 超采样技术可以降低每个像素对计算颜色值和平均值的影响. 简单的方法是将每个像素分层四个子像素, 实现它.

练习3.7: 另一个生成分形图像的方式是使用牛顿法来求解一个复数方程, 例如 z^4 1 = 0. 每个起点到四个根的迭代次数对应阴影的灰度. 方程根对应的点用颜色表示.

练习3.8: 通过提高精度来生成更多级别的分形. 使用四种不同精度类型的数字实现相同的分形: complex64, complex128, big.Float, and big.Rat. (后面两种类型在 math/big 包声明. Float是有指定限精度的浮点数; Rat是无效精度的有理数.) 它们间的性能和内存使用对比如何? 当渲染图可见时缩放的级别是多少?

练习3.9: 编写一个web服务器, 用于给客户端生成分形的图像. 运行客户端用过HTTP参数参数指定x,y和zoom参数.