ch2¶
boiling/main.go¶
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
// See page 29.
//!+
// Boiling prints the boiling point of water.
package main
import "fmt"
const boilingF = 212.0
func main() {
var f = boilingF
var c = (f - 32) * 5 / 9
fmt.Printf("boiling point = %g°F or %g°C\n", f, c)
// Output:
// boiling point = 212°F or 100°C
}
//!-
cf/main.go¶
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
// See page 43.
//!+
// Cf converts its numeric argument to Celsius and Fahrenheit.
package main
import (
"fmt"
"os"
"strconv"
"gopl.io/ch2/tempconv"
)
func main() {
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 := tempconv.Fahrenheit(t)
c := tempconv.Celsius(t)
fmt.Printf("%s = %s, %s = %s\n",
f, tempconv.FToC(f), c, tempconv.CToF(c))
}
}
//!-
echo4/main.go¶
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
// See page 33.
//!+
// Echo4 prints its command-line arguments.
package main
import (
"flag"
"fmt"
"strings"
)
var n = flag.Bool("n", false, "omit trailing newline")
var sep = flag.String("s", " ", "separator")
func main() {
flag.Parse()
fmt.Print(strings.Join(flag.Args(), *sep))
if !*n {
fmt.Println()
}
}
//!-
ftoc/main.go¶
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
// See page 29.
//!+
// Ftoc prints two Fahrenheit-to-Celsius conversions.
package main
import "fmt"
func main() {
const freezingF, boilingF = 32.0, 212.0
fmt.Printf("%g°F = %g°C\n", freezingF, fToC(freezingF)) // "32°F = 0°C"
fmt.Printf("%g°F = %g°C\n", boilingF, fToC(boilingF)) // "212°F = 100°C"
}
func fToC(f float64) float64 {
return (f - 32) * 5 / 9
}
//!-
popcount/main.go¶
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
// See page 45.
// (Package doc comment intentionally malformed to demonstrate golint.)
//!+
package popcount
// pc[i] is the population count of i.
var pc [256]byte
func init() {
for i := range pc {
pc[i] = pc[i/2] + byte(i&1)
}
}
// PopCount returns the population count (number of set bits) of x.
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))])
}
//!-
popcount/popcount_test.go¶
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
package popcount_test
import (
"testing"
"gopl.io/ch2/popcount"
)
// -- Alternative implementations --
func BitCount(x uint64) int {
// Hacker's Delight, Figure 5-2.
x = x - ((x >> 1) & 0x5555555555555555)
x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333)
x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f
x = x + (x >> 8)
x = x + (x >> 16)
x = x + (x >> 32)
return int(x & 0x7f)
}
func PopCountByClearing(x uint64) int {
n := 0
for x != 0 {
x = x & (x - 1) // clear rightmost non-zero bit
n++
}
return n
}
func PopCountByShifting(x uint64) int {
n := 0
for i := uint(0); i < 64; i++ {
if x&(1<<i) != 0 {
n++
}
}
return n
}
// -- Benchmarks --
func BenchmarkPopCount(b *testing.B) {
for i := 0; i < b.N; i++ {
popcount.PopCount(0x1234567890ABCDEF)
}
}
func BenchmarkBitCount(b *testing.B) {
for i := 0; i < b.N; i++ {
BitCount(0x1234567890ABCDEF)
}
}
func BenchmarkPopCountByClearing(b *testing.B) {
for i := 0; i < b.N; i++ {
PopCountByClearing(0x1234567890ABCDEF)
}
}
func BenchmarkPopCountByShifting(b *testing.B) {
for i := 0; i < b.N; i++ {
PopCountByShifting(0x1234567890ABCDEF)
}
}
// Go 1.6, 2.67GHz Xeon
// $ go test -cpu=4 -bench=. gopl.io/ch2/popcount
// BenchmarkPopCount-4 200000000 6.30 ns/op
// BenchmarkBitCount-4 300000000 4.15 ns/op
// BenchmarkPopCountByClearing-4 30000000 45.2 ns/op
// BenchmarkPopCountByShifting-4 10000000 153 ns/op
//
// Go 1.6, 2.5GHz Intel Core i5
// $ go test -cpu=4 -bench=. gopl.io/ch2/popcount
// BenchmarkPopCount-4 200000000 7.52 ns/op
// BenchmarkBitCount-4 500000000 3.36 ns/op
// BenchmarkPopCountByClearing-4 50000000 34.3 ns/op
// BenchmarkPopCountByShifting-4 20000000 108 ns/op
//
// Go 1.7, 3.5GHz Xeon
// $ go test -cpu=4 -bench=. gopl.io/ch2/popcount
// BenchmarkPopCount-12 2000000000 0.28 ns/op
// BenchmarkBitCount-12 2000000000 0.27 ns/op
// BenchmarkPopCountByClearing-12 100000000 18.5 ns/op
// BenchmarkPopCountByShifting-12 20000000 70.1 ns/op
tempconv/conv.go¶
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
// See page 41.
//!+
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) }
//!-
tempconv/tempconv.go¶
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//!+
// Package tempconv performs Celsius and Fahrenheit conversions.
package tempconv
import "fmt"
type Celsius float64
type Fahrenheit float64
const (
AbsoluteZeroC Celsius = -273.15
FreezingC Celsius = 0
BoilingC Celsius = 100
)
func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) }
func (f Fahrenheit) String() string { return fmt.Sprintf("%g°F", f) }
//!-
tempconv0/celsius.go¶
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
// See page 39.
//!+
// Package tempconv performs Celsius and Fahrenheit temperature computations.
package tempconv
import "fmt"
type Celsius float64
type Fahrenheit float64
const (
AbsoluteZeroC Celsius = -273.15
FreezingC Celsius = 0
BoilingC Celsius = 100
)
func CToF(c Celsius) Fahrenheit { return Fahrenheit(c*9/5 + 32) }
func FToC(f Fahrenheit) Celsius { return Celsius((f - 32) * 5 / 9) }
//!-
func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) }
tempconv0/tempconv_test.go¶
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
package tempconv
import "fmt"
func Example_one() {
{
//!+arith
fmt.Printf("%g\n", BoilingC-FreezingC) // "100" °C
boilingF := CToF(BoilingC)
fmt.Printf("%g\n", boilingF-CToF(FreezingC)) // "180" °F
//!-arith
}
/*
//!+arith
fmt.Printf("%g\n", boilingF-FreezingC) // compile error: type mismatch
//!-arith
*/
// Output:
// 100
// 180
}
func Example_two() {
//!+printf
c := FToC(212.0)
fmt.Println(c.String()) // "100°C"
fmt.Printf("%v\n", c) // "100°C"; no need to call String explicitly
fmt.Printf("%s\n", c) // "100°C"
fmt.Println(c) // "100°C"
fmt.Printf("%g\n", c) // "100"; does not call String
fmt.Println(float64(c)) // "100"; does not call String
//!-printf
// Output:
// 100°C
// 100°C
// 100°C
// 100°C
// 100
// 100
}