练习 2.1: 向tempconv包添加类型、常量和函数用来处理Kelvin绝对温度的转换,Kelvin 绝对零度是−273.15°C,Kelvin绝对温度1K和摄氏度1°C的单位间隔是一样的
conv.go
package tempconv
func CToF(c Celsius) Fahrenheit { return Fahrenheit(c*9/5 + 32) }
func CToK(c Celsius) Kelvin { return Kelvin(c + 273.15) }
func FToC(f Fahrenheit) Celsius { return Celsius((f - 32) * 5 / 9) }
func FToK(f Fahrenheit) Kelvin { return Kelvin(((f - 32) * 5 / 9) + 273.15) }
func KToC(k Kelvin) Celsius { return Celsius(k - 273.15) }
func KToF(k Kelvin) Fahrenheit { return Fahrenheit((k-273.15)*9/5 + 32) }
tempconv.go
package tempconv
import "fmt"
type Kelvin float64
type Celsius float64
type Fahrenheit float64
const (
AbsoluteZeroC Celsius = -273.15
FreezingC Celsius = 0
BoilingC Celsius = 100
AbsoluteZeroK Kelvin = 0
FreezingK Kelvin = 273.15
BoilingK Kelvin = 373.15
AbsoluteZeroF Fahrenheit = -459.66999999999996
FreezingF Fahrenheit = 32
BoilingF Fahrenheit = 212
)
func (k Kelvin) String() string { return fmt.Sprintf("%g°K", k) }
func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) }
func (f Fahrenheit) String() string { return fmt.Sprintf("%g°F", f) }
练习 2.2: 写一个通用的单位转换程序,用类似cf程序的方式从命令行读取参数,如果缺省的话则是从标准输入读取参数,然后做类似Celsius和Fahrenheit的单位转换,长度单位可以对应英尺和米,重量单位可以对应磅和公斤等。
程序略
练习 2.3: 重写PopCount函数,用一个循环代替单一的表达式。比较两个版本的性能。(11.4节将展示如何系统地比较两个不同实现的性能。)
package main
var pc [256]byte = func() (pc [256]byte) {
for i := range pc {
pc[i] = pc[i/2] + byte(i&1)
}
return
}()
//func init() {
// for i := range pc {
// pc[i] = pc[i/2] + byte(i&1)
// }
//}
func Popcount(x uint64) int {
return int(pc[byte(x>>(0*8))] +
pc[byte((x>>(1*8)))] +
pc[byte((x>>(2*8)))] +
pc[byte((x>>(3*8)))] +
pc[byte((x>>(4*8)))] +
pc[byte((x>>(5*8)))] +
pc[byte((x>>(6*8)))] +
pc[byte((x>>(7*8)))])
}
func Popcount_Cycle(x uint64) (n int) {
for i := uint(0); i < 8; i++ {
n += int(pc[byte(x>>(i*8))])
}
return
}
练习 2.4: 用移位算法重写PopCount函数,每次测试最右边的1bit,然后统计总数。比较和查表算法的性能差
package main
var pc [256]byte = func() (pc [256]byte) {
for i := range pc {
pc[i] = pc[i/2] + byte(i&1)
}
return
}()
//func init() {
// for i := range pc {
// pc[i] = pc[i/2] + byte(i&1)
// }
//}
func Popcount(x uint64) int {
return int(pc[byte(x>>(0*8))] +
pc[byte((x>>(1*8)))] +
pc[byte((x>>(2*8)))] +
pc[byte((x>>(3*8)))] +
pc[byte((x>>(4*8)))] +
pc[byte((x>>(5*8)))] +
pc[byte((x>>(6*8)))] +
pc[byte((x>>(7*8)))])
}
func Popcount_Cycle(x uint64) (n int) {
for i := uint(0); i < 8; i++ {
n += int(pc[byte(x>>(i*8))])
}
return
}
func PopCountByRightMostBit(x uint64) (n int) {
for i := uint(0); i < 64; i++ {
if x&1 != 0 {
n++
}
x >>= 1
}
return
}
练习 2.5: 表达式 x&(x-1) 用于将x的最低的一个非零的bit位清零。使用这个算法重写PopCount函数,然后比较性
package main
var pc [256]byte = func() (pc [256]byte) {
for i := range pc {
pc[i] = pc[i/2] + byte(i&1)
}
return
}()
//func init() {
// for i := range pc {
// pc[i] = pc[i/2] + byte(i&1)
// }
//}
func Popcount(x uint64) int {
return int(pc[byte(x>>(0*8))] +
pc[byte((x>>(1*8)))] +
pc[byte((x>>(2*8)))] +
pc[byte((x>>(3*8)))] +
pc[byte((x>>(4*8)))] +
pc[byte((x>>(5*8)))] +
pc[byte((x>>(6*8)))] +
pc[byte((x>>(7*8)))])
}
func Popcount_Cycle(x uint64) (n int) {
for i := uint(0); i < 8; i++ {
n += int(pc[byte(x>>(i*8))])
}
return
}
func PopCountByRightMostBit(x uint64) (n int) {
for i := uint(0); i < 64; i++ {
if x&1 != 0 {
n++
}
x >>= 1
}
return
}
func PopCountByClearing(x uint64) (n int) {
for x != 0 {
x = x & (x - 1)
n++
}
return
}