mirror of
https://github.com/unknwon/the-way-to-go_ZH_CN.git
synced 2025-08-12 07:34:06 +08:00
Merge branch 'master' of https://github.com/dbarobin/the-way-to-go_ZH_CN
# Conflicts: # eBook/09.5.md
This commit is contained in:
@@ -1 +1,54 @@
|
|||||||
# 精密计算和 big 包
|
# 9.4 精密计算和 big 包
|
||||||
|
|
||||||
|
我们知道有些时候通过编程的方式去进行计算是不精确的。如果你使用 Go 语言中的 float64 类型进行浮点运算,返回结果将精确到 15 位,足以满足大多数的任务。当对超出 int64 或者 uint64 类型这样的大数进行计算时,如果对精度没有要求,float32 或者 float64 可以胜任,但如果对精度有严格要求的时候,我们不能使用浮点数,在内存中它们只能被近似的表示。
|
||||||
|
|
||||||
|
对于整数的高精度计算 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` 类型的临时变量来存放中间结果,所以这样的运算可通过内存链式存储。
|
||||||
|
|
||||||
|
示例 9.2 [big.go](examples/chapter_9/big.go):
|
||||||
|
|
||||||
|
``` go
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Output:
|
||||||
|
Big Int: 43492122561469640008497075573153004
|
||||||
|
Big Rat: -37/112
|
||||||
|
*/
|
||||||
|
```
|
||||||
|
|
||||||
|
输出结果:
|
||||||
|
|
||||||
|
Big Int: 43492122561469640008497075573153004
|
||||||
|
Big Rat: -37/112
|
||||||
|
|
||||||
|
## 链接
|
||||||
|
|
||||||
|
- [目录](directory.md)
|
||||||
|
- 上一节:[锁和 sync 包](09.3.md)
|
||||||
|
- 下一节:[自定义包和可见性](09.5.md)
|
||||||
|
@@ -23,7 +23,7 @@ func ReturnStr() string {
|
|||||||
在主程序 pack_test.go 中这个包通过声明的方式被导入
|
在主程序 pack_test.go 中这个包通过声明的方式被导入
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import “./pack1/pack1”
|
import "./pack1/pack1"
|
||||||
```
|
```
|
||||||
|
|
||||||
import 的一般格式如下:
|
import 的一般格式如下:
|
||||||
@@ -36,7 +36,7 @@ import 的一般格式如下:
|
|||||||
|
|
||||||
路径是指当前目录的相对路径。
|
路径是指当前目录的相对路径。
|
||||||
|
|
||||||
示例 9.5 [package_test.go](examples/chapter_9/package_test.go):
|
示例 9.5 [package_test.go](examples/chapter_9/book/package_test.go):
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -50,8 +50,8 @@ func main() {
|
|||||||
var test1 string
|
var test1 string
|
||||||
test1 = pack1.ReturnStr()
|
test1 = pack1.ReturnStr()
|
||||||
fmt.Printf("ReturnStr from package1: %s\n", test1)
|
fmt.Printf("ReturnStr from package1: %s\n", test1)
|
||||||
fmt.Printf(“Integer from package1: %d\n”, pack1.Pack1Int)
|
fmt.Printf("Integer from package1: %d\n", pack1.Pack1Int)
|
||||||
// fmt.Printf(“Float from package1: %f\n”, pack1.pack1Float)
|
// fmt.Printf("Float from package1: %f\n", pack1.pack1Float)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -76,13 +76,13 @@ fmt.Printf(“Float from package1: %f\n”, pack1.pack1Float)
|
|||||||
|
|
||||||
因此,按照惯例子目录和包之间有着密切的联系:为了区分不同包存放在不同的目录,每个包(所有属于这个包中的 go 文件)都存放在和包名相同的子目录下:
|
因此,按照惯例子目录和包之间有着密切的联系:为了区分不同包存放在不同的目录,每个包(所有属于这个包中的 go 文件)都存放在和包名相同的子目录下:
|
||||||
|
|
||||||
**Import with .** : import . “./pack1”
|
**Import with .** : import . "./pack1"
|
||||||
|
|
||||||
当使用.来做为包的别名时,你可以不通过包名来使用其中的项目。例如:`test := ReturnStr()`。
|
当使用.来做为包的别名时,你可以不通过包名来使用其中的项目。例如:`test := ReturnStr()`。
|
||||||
|
|
||||||
在当前的命名空间导入 pack1 包,一般是为了具有更好的测试效果。
|
在当前的命名空间导入 pack1 包,一般是为了具有更好的测试效果。
|
||||||
|
|
||||||
**Import with _** : import _ “./pack1/pack1”
|
**Import with _** : import _ "./pack1/pack1"
|
||||||
|
|
||||||
pack1包只导入其副作用,也就是说,只执行它的init函数并初始化其中的全局变量。
|
pack1包只导入其副作用,也就是说,只执行它的init函数并初始化其中的全局变量。
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ pack1包只导入其副作用,也就是说,只执行它的init函数并初
|
|||||||
|
|
||||||
通过以下方式,一次性安装,并导入到你的代码中:
|
通过以下方式,一次性安装,并导入到你的代码中:
|
||||||
|
|
||||||
import goex “codesite.ext/author/goExample/goex”
|
import goex "codesite.ext/author/goExample/goex"
|
||||||
|
|
||||||
因此该包的 URL 将用作导入路径。
|
因此该包的 URL 将用作导入路径。
|
||||||
|
|
||||||
|
@@ -26,12 +26,67 @@ sort 包
|
|||||||
```go
|
```go
|
||||||
func Float64sAreSorted
|
func Float64sAreSorted
|
||||||
|
|
||||||
type IntArray
|
type IntArray
|
||||||
|
|
||||||
func IntsAreSortedfunc IsSortedfunc Sort
|
func IntsAreSortedfunc IsSortedfunc Sort
|
||||||
|
|
||||||
func (IntArray) Len
|
func (IntArray) Len
|
||||||
|
|
||||||
func SortFloat64s
|
func SortFloat64s
|
||||||
|
|
||||||
|
func (IntArray) Less
|
||||||
|
|
||||||
|
func SortInts
|
||||||
|
|
||||||
|
func (IntArray) Swap
|
||||||
|
|
||||||
|
func SortStrings type Interface
|
||||||
|
|
||||||
|
func StringsAreSorted type StringArray type Float64Array
|
||||||
|
|
||||||
|
func (StringArray) Len
|
||||||
|
|
||||||
|
func (Float64Array) Len
|
||||||
|
|
||||||
|
func (StringArray) Less
|
||||||
|
|
||||||
|
func (Float64Array) Less
|
||||||
|
|
||||||
|
func (StringArray) Swap
|
||||||
|
|
||||||
|
func (Float64Array) Swap
|
||||||
|
|
||||||
|
Other packages
|
||||||
|
import "doc_example"
|
||||||
```
|
```
|
||||||
func (IntArray) Less
|
|
||||||
|
使用通用的接口排序:
|
||||||
|
```
|
||||||
|
func Float64sAreSorted[Top]
|
||||||
|
func Float64sAreSorted(a []float64) bool
|
||||||
|
|
||||||
|
func IntsAreSorted[Top]
|
||||||
|
func IntsAreSorted(a []int) bool
|
||||||
|
|
||||||
|
func IsSorted[Top]
|
||||||
|
func IsSorted(data Interface) bool
|
||||||
|
Test if data is sorted
|
||||||
|
|
||||||
|
func Sort[Top]
|
||||||
|
func Sort(data Interface)
|
||||||
|
General sort function
|
||||||
|
|
||||||
|
func SortInts[Top]
|
||||||
|
func SortInts(a []int)
|
||||||
|
|
||||||
|
Convenience wrappers for common cases: type IntArray[Top]
|
||||||
|
Convenience types for common cases: IntArray type IntArray []int
|
||||||
|
```
|
||||||
|
|
||||||
|
如果你在一个团队中工作,并在源代码树被存储在网络硬盘上,就可以使用 godoc 给所有团队成员连续文档的支持。通过设置 sync_minutes=n,你甚至可以让它每 n 分钟自动更新您的文档!
|
||||||
|
|
||||||
|
## 链接
|
||||||
|
|
||||||
|
- [目录](directory.md)
|
||||||
|
- 上一节:[自定义包和可见性](09.5.md)
|
||||||
|
- 下一节:[使用 go install 安装自定义包](09.7.md)
|
||||||
|
23
eBook/examples/chapter_9/test.go
Normal file
23
eBook/examples/chapter_9/test.go
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package uc
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
type ucTest struct {
|
||||||
|
in, out string
|
||||||
|
}
|
||||||
|
|
||||||
|
var ucTests = []ucTest{
|
||||||
|
ucTest{"abc", "ABC"},
|
||||||
|
ucTest{"cvo-az", "CVO-AZ"},
|
||||||
|
ucTest{"Antwerp", "ANTWERP"},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUC(t *testing.T) {
|
||||||
|
for _, ut := range ucTests {
|
||||||
|
uc := UpperCase(ut.in)
|
||||||
|
if uc != ut.out {
|
||||||
|
t.Errorf("UpperCase(%s) = %s, must be %s", ut.in, uc,
|
||||||
|
ut.out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
eBook/examples/chapter_9/uc.go
Normal file
7
eBook/examples/chapter_9/uc.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package uc
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
func UpperCase(str string) string {
|
||||||
|
return strings.ToUpper(str)
|
||||||
|
}
|
11
eBook/examples/chapter_9/ucmain.go
Normal file
11
eBook/examples/chapter_9/ucmain.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"./uc/uc"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
str1 := "USING package uc"
|
||||||
|
fmt.Println(uc.UpperCase(str1))
|
||||||
|
}
|
Reference in New Issue
Block a user