【go语言圣经】习题答案 第三章

3.1 修改无限制的float64值,跳过无效的多边形

// 只需修改f函数
func f(x, y float64) float64 {
	r := math.Hypot(x, y) // distance from (0,0)
	if math.IsInf(r, 0) || math.IsNaN(r) {
		return 0
	}
	return math.Sin(r) / r
}

3.2 试验math包中其他函数的渲染图形 马鞍面

// 只需替换f函数
func corner(i, j int) (float64, float64) {
	// Find point (x,y) at corner of cell (i,j).
	x := xyrange * (float64(i)/cells - 0.5)
	y := xyrange * (float64(j)/cells - 0.5)
	// Compute surface height z.
	z := f_saddle(x, y)
	// Project (x,y,z) isometrically onto 2-D SVG canvas (sx,sy).
	sx := width/2 + (x-y)*cos30*xyscale
	sy := height/2 + (x+y)*sin30*xyscale - z*zscale
	return sx, sy
}

func f_saddle(x, y float64) float64 {
	return x*x/600 - y*y/600
}

3.3根据高度给每个多边形上色

颜色确实是画出来了,就是真的好丑hhhh

func corner(i, j int) (float64, float64, float64) {
	// Find point (x,y) at corner of cell (i,j).
	x := xyrange * (float64(i)/cells - 0.5)
	y := xyrange * (float64(j)/cells - 0.5)
	// Compute surface height z.
	z := f(x, y) 		//保存高度用于设置颜色
	// Project (x,y,z) isometrically onto 2-D SVG canvas (sx,sy).
	sx := width/2 + (x-y)*cos30*xyscale
	sy := height/2 + (x+y)*sin30*xyscale - z*zscale
	return sx, sy, z
}
func f(x, y float64) float64 {
	r := math.Hypot(x, y) // distance from (0,0)
	if math.IsInf(r, 0) || math.IsNaN(r) {
		return 0
	}
	return math.Sin(r) / r
}

func f_saddle(x, y float64) float64 {
	return x*x/600 - y*y/600
}

func test_3_3() {
	f, err := os.OpenFile("./pic.svg", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
	if err != nil {
		fmt.Println("file open failed: ", err)
	}
	defer f.Close()
	fmt.Fprintf(f, "<svg xmlns='http://www.w3.org/2000/svg' "+
		"style='stroke: grey; fill: white; stroke-width: 0.7' "+
		"width='%d' height='%d'>", width, height)
	for i := 0; i < cells; i++ {
		for j := 0; j < cells; j++ {
			ax, ay, az := corner(i+1, j)
			bx, by, bz := corner(i, j)
			cx, cy, cz := corner(i, j+1)
			dx, dy, dz := corner(i+1, j+1)
			height := (az + bz + cz + dz) / 4 	// 取四个顶点的高度平均值
			red, blue := 0, 0
			if height > 0 {
				red = int(height * 256)  // 如果高度为正则显示红色,否则显示蓝色
			} else {
				blue = int(-height * 256)
			}
			fmt.Fprintf(f, "<polygon points='%g,%g %g,%g %g,%g %g,%g' style=\"fill: #%02x00%02x;\"/>\n",
				ax, ay, bx, by, cx, cy, dx, dy, red, blue)
		}
	}
	fmt.Fprintln(f, "</svg>")
}

3.4 构造web服务器,返回SVG数据给客户端

var (
	width, height = 600, 320                     // canvas size in pixels
	cells         = 100                          // number of grid cells
	xyrange       = 30.0                         // axis ranges (-xyrange..+xyrange)
	xyscale       = float64(width) / 2 / xyrange // pixels per x or y unit
	zscale        = float64(height) * 0.4        // pixels per z unit
	angle         = math.Pi / 6                  // angle of x, y axes (=30°)
	color         = "000000"                     //color of picture
)

var sin30, cos30 = math.Sin(angle), math.Cos(angle) // sin(30°), cos(30°)

func corner(i, j int) (float64, float64) {
	// Find point (x,y) at corner of cell (i,j).
	x := xyrange * (float64(i)/float64(cells) - 0.5)
	y := xyrange * (float64(j)/float64(cells) - 0.5)
	// Compute surface height z.
	z := f(x, y)
	// Project (x,y,z) isometrically onto 2-D SVG canvas (sx,sy).
	sx := float64(width)/2 + (x-y)*cos30*xyscale
	sy := float64(height)/2 + (x+y)*sin30*xyscale - z*zscale
	return sx, sy
}

func f(x, y float64) float64 {
	r := math.Hypot(x, y) // distance from (0,0)
	if math.IsInf(r, 0) || math.IsNaN(r) {
		return 0
	}
	return math.Sin(r) / r
}

func test_3_4(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "image/svg+xml")
	err := r.ParseForm()
	if err != nil {
		fmt.Fprintln(w, "request parse error: ", err)
	}
	// 判断query参数是否有效,无效则使用默认值
	if w := r.Form.Get("width"); w != "" {
		width, _ = strconv.Atoi(w)
	}
	if h := r.Form.Get("height"); h != "" {
		height, _ = strconv.Atoi(h)
	}
	if c := r.Form.Get("color"); c != "" {
		color = r.Form.Get("color")
	}
	fmt.Fprintf(w, "<svg xmlns='http://www.w3.org/2000/svg' "+
		"style='stroke: grey; fill: white; stroke-width: 0.7' "+
		"width='%d' height='%d'>", width, height)
	for i := 0; i < cells; i++ {
		for j := 0; j < cells; j++ {
			ax, ay := corner(i+1, j)
			bx, by := corner(i, j)
			cx, cy := corner(i, j+1)
			dx, dy := corner(i+1, j+1)
			fmt.Fprintf(w, "<polygon points='%g,%g %g,%g %g,%g %g,%g' style=\"fill: #%s;\"/>\n",
				ax, ay, bx, by, cx, cy, dx, dy, color)
		}
	}
	fmt.Fprintln(w, "</svg>")
}

func main() {
	http.HandleFunc("/", test_3_4)
	err := http.ListenAndServe(":9999", nil)
	if err != nil {
		fmt.Println("server listen error: ", err)
	}
}

3.5 实现一个彩色的Mandelbrot图像

// 只需修改mandelbrot函数
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.RGBA{255, 125, 1, 255 - contrast*n}
		}
	}
	return color.Black
}

3.6 实现升采样技术

不确定理解的对不对,但这不是将width, height都扩大两倍就可以实现的吗?

	const (
		xmin, ymin, xmax, ymax = -2, -2, +2, +2
		width, height          = 2048, 2048
	)

3.7 使用牛顿法来求解一个复数方程( z 4 − 1 = 0 z^4-1=0 z41=0)生成分形图像

// 用于求解的方称
func f(x complex128) complex128 {
	return x*x*x*x - 1
}

// 该方程的导数
func fd(x complex128) complex128 {
	return 4 * x * x * x
}

// 使用牛顿法求解方程f
func someEquation(z complex128) color.Color {
	var times uint8 = 0
	for (cmplx.Abs(f(z)) > 0.0001) && (times < 255) { //当f(z)约等于0或循环次数超过255时结束循环
		times++
		z = z - f(z)/fd(z) //牛顿法求解
	}
	return color.Gray{255 - times}
}

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))
			img.Set(px, py, someEquation(z))
		}
	}
	f, err := os.OpenFile("./someEquation.png", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
	if err != nil {
		fmt.Println("file open failed,err:", err)
	}
	defer f.Close()
	png.Encode(f, img) // NOTE: ignoring errors
}

3.8 通过提高精度来生成更多级别的分形

func mandelbrot(z complex64) color.Color {
	const iterations = 200
	const contrast = 15
	var v complex64
	for n := uint8(0); n < iterations; n++ {
		v = v*v + z
		if real(v)*real(v)+imag(v)*imag(v) > 2 {
			// return color.Gray{255 - contrast*n}
			return color.RGBA{255, 125, 1, 255 - contrast*n}
		}
	}
	return color.Black
}
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 := float32(py)/height*(ymax-ymin) + ymin
		for px := 0; px < width; px++ {
			x := float32(px)/width*(xmax-xmin) + xmin
			z := complex(x, y)
			// Image point (px, py) represents complex value z.
			img.Set(px, py, mandelbrot(z))
		}
	}
	f, err := os.OpenFile("./image/mandelbrot_complex64.png", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
	if err != nil {
		fmt.Println("file open failed,err:", err)
	}
	defer f.Close()
	png.Encode(f, img) // NOTE: ignoring errors
}

3.9 web服务器,用于给客户端生成分形的图像

不确定这个zoom参数的意思是否理解正确,有问题欢迎指正

func Fractal(f io.Writer, width int, height int) {
	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)/float64(height)*(ymax-ymin) + ymin
		for px := 0; px < width; px++ {
			x := float64(px)/float64(width)*(xmax-xmin) + xmin
			z := complex(x, y)
			// Image point (px, py) represents complex value z.
			img.Set(px, py, mandelbrot(z))
		}
	}
	png.Encode(f, img) // NOTE: ignoring errors
}

func test_3_9(w http.ResponseWriter, r *http.Request) {
	// 从HTTP参数中获取长、宽、放大倍数
	r.ParseForm()
	width, height, zoom := 1024, 1024, 1
	if s := r.Form.Get("x"); s != "" {
		width, _ = strconv.Atoi(s)
	}
	if s := r.Form.Get("y"); s != "" {
		height, _ = strconv.Atoi(s)
	}
	if s := r.Form.Get("zoom"); s != "" {
		zoom, _ = strconv.Atoi(s)
	}
	Fractal(w, width*zoom, height*zoom)
}

// web服务器,用于给客户端生成分形的图像
func main() {
	http.HandleFunc("/", test_3_9)
	if err := http.ListenAndServe(":9999", nil); err != nil {
		fmt.Println("server listen error,err:", err)
	}
}

3.10 非递归版本的comma函数,使用bytes.Buffer

// 非递归版本的comma函数,使用bytes.Buffer
func test_3_10(s string) {
	len := len(s)
	var buf bytes.Buffer
	for i := 0; i < len%3; i++ {
		buf.WriteByte(s[i])
	}
	if len%3 != 0 {
		buf.WriteByte(',')
	}
	for i := len % 3; i < len; {
		buf.WriteString(s[i : i+3])
		i += 3
		if i != len { // 不是最后一组均写入','
			buf.WriteByte(',')
		}
	}
	fmt.Println(buf.String())
}

func main() {
	var num string
	fmt.Print("please input a number:")
	_, _ = fmt.Scanln(&num)
	test_3_10(num)
}

3.11 支持浮点数处理和一个可选的正负号的处理

// 非递归版本的comma函数,使用bytes.Buffer,支持可选的+,-号
func test_3_10(s string) string {
	len := len(s)
	var buf bytes.Buffer
	for i := 0; i < len%3; i++ {
		buf.WriteByte(s[i])
	}
	if len%3 != 0 {
		buf.WriteByte(',')
	}
	for i := len % 3; i < len; {
		buf.WriteString(s[i : i+3])
		i += 3
		if i != len { // 不是最后一组均写入','
			buf.WriteByte(',')
		}
	}
	// fmt.Println(buf.String())
	return buf.String()
}

func test_3_11(num string) string {
	index := strings.LastIndex(num, ".")
	if index == -1 {
		return test_3_10(num) //不是浮点数直接返回
	} else {
		return test_3_10(num[:index]) + "." + num[index+1:] //浮点数先处理整数部分再连接后面浮点数返回
	}
}

func main() {
	var num string
	fmt.Print("please input a number:")
	_, _ = fmt.Scanln(&num)
	fmt.Println(test_3_11(num))
}

3.12 判断两个字符串是否是是相互打乱的

// 判断两个字符串是否是是相互打乱的
func test_3_12(s1, s2 string) bool {
	m := make(map[rune]int)
	for _, c := range s1 {
		m[c]++
	}
	for _, c := range s2 {
		m[c]--
	}
	for _, v := range m {
		if v != 0 {
			return false
		}
	}
	return true
}

func main() {
	s1, s2 := "sdfghjkuytfvb", "kjhgfdstyubvf"
	fmt.Printf("first string is :%s\nsecond string is :%s\n", s1, s2)
	if test_3_12(s1, s2) {
		fmt.Println("them have same characters")
	} else {
		fmt.Printf("they don't have different characters")
	}
}

3.13 编写KB、MB的常量声明

const (
	KB = 1000
	MB = 1000 * KB
	GB = 1000 * MB
	TB = 1000 * GB
	PB = 1000 * TB
	EB = 1000 * PB
	ZB = 1000 * EB
	YB = 1000 * ZB
)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值