练习2.1
向tempconv包添加类型、常量和函数用来处理Kelvin绝对温度的转换,Kelvin 绝对零度是−273.15°C,Kelvin绝对温度1K和摄氏度1°C的单位间隔是一样的。
conv.go
package tempconv// CToF converts a Celsius temperature to Fahrenheit.
func CToF(c Celsius) Fahrenheit { return Fahrenheit(c*9/5 + 32) }// FToC converts a Fahrenheit temperature to Celsius.
func FToC(f Fahrenheit) Celsius { return Celsius((f - 32) * 5 / 9) }func KToC(k Kelvin) Celsius { return Celsius(k + 273.15) }func CToT(c Celsius) Kelvin { return Kelvin(c + 273.15) }
tempconv.go
package tempconvimport "fmt"type Celsius float64
type Fahrenheit float64
type Kelvin float64const (AbsoluteZeroC Celsius = -273.15FreezingC Celsius = 0BoilingC Celsius = 100
)func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) }
func (f Fahrenheit) String() string { return fmt.Sprintf("%g°F", f) }
func (k Kelvin) String() string { return fmt.Sprintf("%g°K", k) }
练习2.2
写一个通用的单位转换程序,用类似cf程序的方式从命令行读取参数,如果缺省的话则是从标准输入读取参数,然后做类似Celsius和Fahrenheit的单位转换,长度单位可以对应英尺和米,重量单位可以对应磅和公斤等。
conv.go:
package lenthconvfunc MToF(m Meter) Feet { return Feet(m / 0.3084) }func FToM(f Feet) Meter { return Meter(f * 0.3084) }
lenthconv:
package lenthconvimport "fmt"type Meter float64
type Feet float64func (m Meter) String() string { return fmt.Sprintf("%g m", m) }
func (f Feet) String() string { return fmt.Sprintf("%g ft", f) }
test:
package mainimport ("bufio""fmt""os""strconv""gopl.io/ch2/lenthconv"
)func main() {if len(os.Args) == 1 {input := bufio.NewScanner(os.Stdin)for input.Scan() {t, err := strconv.ParseFloat(input.Text(), 64)if err != nil {fmt.Fprintf(os.Stderr, "cf: %v\n", err)os.Exit(1)}f := lenthconv.Feet(t)m := lenthconv.Meter(t)fmt.Printf("%s = %s, %s = %s\n",f, lenthconv.FToM(f), m, lenthconv.MToF(m))}}for _, arg := range os.Args[1:] {t, err := strconv.ParseFloat(arg, 64)if err != nil {fmt.Fprintf(os.Stderr, "cf: %v\n", err)os.Exit(1)}f := lenthconv.Feet(t)m := lenthconv.Meter(t)fmt.Printf("%s = %s, %s = %s\n",f, lenthconv.FToM(f), m, lenthconv.MToF(m))}
}
练习2.3
重写PopCount函数,用一个循环代替单一的表达式。比较两个版本的性能。
func PopCount(x uint64) int {res := 0for i := 0; i < 8; i++ {res += int(pc[byte(x>>(i*8))])}return res
}
练习2.4
用移位算法重写PopCount函数,每次测试最右边的1bit,然后统计总数。比较和查表算法的性能差异。
func PopCount(x uint64) int {res := 0for x != 0 {res += x & 1x >>= 1}return res
}
练习2.5
表达式x&(x-1)用于将x的最低的一个非零的bit位清零。使用这个算法重写PopCount函数,然后比较性能。
func PopCount(x uint64) int {res := 0for x != 0 {res++x &= x - 1}return res
}