diff --git a/README.md b/README.md index 2ebe3de..067b39f 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ ## 翻译进度 -9.3 [锁和 sync 包](eBook/09.3.md) +9.4 [精密计算和 big 包](eBook/09.4.md) ## 支持本书 diff --git a/eBook/09.4.md b/eBook/09.4.md index fd44a21..afe724c 100644 --- a/eBook/09.4.md +++ b/eBook/09.4.md @@ -1,15 +1,22 @@ # 精密计算和 big 包 -202 -我们知道有些时候通过编程的方式去进行计算是不精确的。如果你使用Go语言中的fload64类型进行浮点运算,返回结果将精确到15位,足以满足大多数的任务。当对超出in64或者uint64类型这样的大数进行计算时,如果对精度没有要求,float32或者float64可以胜任,但如果对精度有严格要求的时候,我们不能使用浮点数,在内存中它们只能被近似的表示。 +我们知道有些时候通过编程的方式去进行计算是不精确的。如果你使用 Go 语言中的 fload64 类型进行浮点运算,返回结果将精确到 15 位,足以满足大多数的任务。当对超出 int64 或者 uint64 类型这样的大数进行计算时,如果对精度没有要求,float32 或者 float64 可以胜任,但如果对精度有严格要求的时候,我们不能使用浮点数,在内存中它们只能被近似的表示。 -对于整数的高精度计算Go语言中提供了big包。其中包含了math包:有用来表示大整数的big.Int和表示大有理数的big.Rat类型(可以表示为2/5或3.1416这样的分数,而不是无理数或π)。这些类型可以实现任意位类型的数字,只要内存足够大。缺点是更大的内存和处理开销使它们使用起来要比内置的数字类型慢很多。 +对于整数的高精度计算 Go 语言中提供了 big 包。其中包含了 math 包:有用来表示大整数的 `big.Int` 和表示大有理数的 `big.Rat` 类型(可以表示为 2/5 或 3.1416 这样的分数,而不是无理数或 π)。这些类型可以实现任意位类型的数字,只要内存足够大。缺点是更大的内存和处理开销使它们使用起来要比内置的数字类型慢很多。 -大的整型数字是通过big.NewInt(n)来构造的,其中n位int64类型整数。而大有理数是用过big.NewRat(N,D)方法构造.N(分子)和D(分母)都是int64型整数。因为Go语言不支持运算符重载,所以所有大数字类型都有像是Add()和Mul()这样的方法。它们作用于作为receiver的整数和有理数,大多数情况下它们修改receiver并以receiver作为返回结果。因为没有必要创建big.Int类型的临时变量来存放中间结果,所以这样的运算可通过内存链式存储。 +大的整型数字是通过 `big.NewInt(n)` 来构造的,其中 n 位 int64 类型整数。而大有理数是用过 `big.NewRat(N,D)` 方法构造。N(分子)和 D(分母)都是 int64 型整数。因为 Go 语言不支持运算符重载,所以所有大数字类型都有像是 Add() 和 Mul() 这样的方法。它们作用于作为 receiver 的整数和有理数,大多数情况下它们修改 receiver 并以 receiver 作为返回结果。因为没有必要创建 big.Int 类型的临时变量来存放中间结果,所以这样的运算可通过内存链式存储。 -示例 9.2 [big.go](examples/chapter_9/big.go) +示例 9.2 [big.go](examples/chapter_9/big.go): - package main import ( "fmt" "math"" "math/big" ) func main() { // Here are some calculations with bigInts: im := big.NewInt(math.MaxInt64) in := im io := big.NewInt(1956) ip := big.NewInt(1) ip.Mul(im, in).Add(ip, im).Div(ip, io) fmt.Printf(“Big Int: %v\n”, ip) // Here are some calculations with bigInts: rm := big.NewRat(math.MaxInt64, 1956) rn := big.NewRat(-1956, math.MaxInt64) ro := big.NewRat(19, 56) rp := big.NewRat(1111, 2222) rq := big.NewRat(1, 1) rq.Mul(rm, rn).Add(rq, ro).Mul(rq, rp) fmt.Printf(“Big Rat: %v\n”, rq) } +```go +package main import ( "fmt" "math"" "math/big" ) func main() { // Here are some calculations with bigInts: im := big.NewInt(math.MaxInt64) in := im io := big.NewInt(1956) ip := big.NewInt(1) ip.Mul(im, in).Add(ip, im).Div(ip, io) fmt.Printf("Big Int: %v\n", ip) // Here are some calculations with bigInts: rm := big.NewRat(math.MaxInt64, 1956) rn := big.NewRat(-1956, math.MaxInt64) ro := big.NewRat(19, 56) rp := big.NewRat(1111, 2222) rq := big.NewRat(1, 1) rq.Mul(rm, rn).Add(rq, ro).Mul(rq, rp) fmt.Printf("Big Rat: %v\n", rq) } +``` 输出结果: Big Int: 43492122561469640008497075573153004 Big Rat: -37/112 + +## 链接 + +- [目录](directory.md) +- 上一节:[锁和 sync 包](09.3.md) +- 下一节:[自定义包和可见性](09.5.md) diff --git a/eBook/09.5.md b/eBook/09.5.md index 5164713..0d693c4 100755 --- a/eBook/09.5.md +++ b/eBook/09.5.md @@ -1,6 +1,6 @@ -#B 自定义和外部包的使用,编译,测试,文档和安装 -#9.5 自定义包和可见性 +# 9.5 自定义包和可见性 +203 包是Go语言中代码组成和代码编译的主要方式。很多关于它们的基本信息已经在4.2章节中给出,最引人注目的便是可见性。现在我们来看看具体如何来使用自己写的包。在下一节,我们将回顾一些标准库中的包,自定义的包和标准库以外的包。 当写自己包的时候,要使用短小的不含有_(下划线)的小写单词来为文件命名。这里有个简单例子来说明包是如何相互调用以及可见性是如何实现的。 @@ -12,47 +12,47 @@ package pack1 var Pack1Int int = 42 var PackFloat = 3.14 - + func ReturnStr() string { return "Hello main!" } - + 它包含了一个整型变量PackInt和一个返回字符串的函数ReturnStr。这段程序在运行时不做任何的事情,因为它不包含有一个main函数。 在主程序pack_test.go中这个包通过声明的方式被导入 - import “./pack1/pack1” import的一般格式如下: + import “./pack1/pack1” import的一般格式如下: import “包的路径或url地址“ 像 import "github.com/org1/pack1” 路径是指当前目录的相对路径。 示例 9.5 [package_test.go](examples/chapter_9/package_test.go) - + package main import ( "fmt" "./pack1/pack1" ) - + func main() { var test1 string test1 = pack1.ReturnStr() fmt.Printf("ReturnStr from package1: %s\n", test1) fmt.Printf(“Integer from package1: %d\n”, pack1.Pack1Int) // fmt.Printf(“Float from package1: %f\n”, pack1.pack1Float) - + 输出结果: - ReturnStr from package1: Hello main! Integer from package1: 42 - + ReturnStr from package1: Hello main! Integer from package1: 42 + 如果包pack1和我们的程序在统同一路径下,我们可以通过"import ./pack1"这样的方式来引入,但这不被视为一个好的方法。 fmt.Printf(“Float from package1: %f\n”, pack1.pack1Float)这行代码试图访问一个未引用的变量或者函数,甚至没有编译。将会返回一个错误: cannot refer to unexported name pack1.pack1Float - -主程序利用的包必须在主程序编写之前被编译。主程序中每个pack1项目都要通过包名来使用使用:pack1.Item。具体使用方法请参见示例4.6和4.7。 - + +主程序利用的包必须在主程序编写之前被编译。主程序中每个pack1项目都要通过包名来使用使用:pack1.Item。具体使用方法请参见示例4.6和4.7。 + 因此,按照惯例子目录和包之间有着密切的联系:为了区分不同包存放在不同的目录,每个包(所有属于这个包中的go文件)都存放在和包名相同的子目录下。 Import with . : import . “./pack1” - + 当使用.来做为包的别名时,你可以不通过包名来使用其中的项目。例如:test := ReturnStr()。 在当前的命名空间导入pack1包,一般是为了具有更好的测试效果。 @@ -75,7 +75,7 @@ pack1包只导入其副作用,只执行了它的init函数并初始化了其 通过以下方式,一次性安装,并导入到你的代码中: import goex “codesite.ext/author/goExample/goex” - + 因此你项目的路径将成为导入包的网络地址 在http://golang.org/cmd/goinstall/的go install文档中列出了一些广泛被使用的托管在网络代码仓库的包的导入路径 @@ -103,7 +103,7 @@ init函数是不能被调用的。 go install(参见9.7章节,从Go1的首选方式)同样复制pack1.a到本地的$GOROOT/pkg的目录中一个以操作系统为名的子目录下。像 import "pack1"代替imort "path to pack1",这样只通过名字就可以将包在程序中导入。 如果不可取或不被允许,通过6/8g使用-I选项来编译: - + 6g—I map_pack1 package_test.go # where map_pack1 is the map which contains pack1.a (I选项让编译器查找选项后的目录下是否包含这个包) 使用6/8l的-L选项链接: 6l—L map_pack1 package_test.6 @@ -132,8 +132,6 @@ go install(参见9.7章节,从Go1的首选方式)同样复制pack1.a到本地 (1)将斐波那契功能放入自己的fibo包中并通过主程序调用它,存储最后输入的值在函数的全局变量。 -(2)扩展fibo包将通过调用斐波那契的时候,操作也作为一个参数。实验"+"和“*” +(2)扩展fibo包将通过调用斐波那契的时候,操作也作为一个参数。实验"+"和“*” main_fibo.go / fibonacci.go - - diff --git a/eBook/directory.md b/eBook/directory.md index e9befb1..2202100 100644 --- a/eBook/directory.md +++ b/eBook/directory.md @@ -77,6 +77,7 @@ - 9.2 [regexp 包](09.2.md) - 9.3 [锁和 sync 包](09.3.md) - 9.4 [精密计算和 big 包](09.4.md) + - 9.5 [自定义包和可见性](09.5.md) - 第10章:结构(struct)与方法(method) - 第11章:接口(interface)与反射(reflection)