第三章练习题答案
- 3.1 修改无限制的float64值,跳过无效的多边形
- 3.2 试验math包中其他函数的渲染图形 马鞍面
- 3.3根据高度给每个多边形上色
- 3.4 构造web服务器,返回SVG数据给客户端
- 3.5 实现一个彩色的Mandelbrot图像
- 3.6 实现升采样技术
- 3.7 使用牛顿法来求解一个复数方程( z 4 − 1 = 0 z^4-1=0 z4−1=0)生成分形图像
- 3.8 通过提高精度来生成更多级别的分形
- 3.9 web服务器,用于给客户端生成分形的图像
- 3.10 非递归版本的comma函数,使用bytes.Buffer
- 3.11 支持浮点数处理和一个可选的正负号的处理
- 3.12 判断两个字符串是否是是相互打乱的
- 3.13 编写KB、MB的常量声明
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 z4−1=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
)