- 前言
- Go 与操作系统
- Go 内部机制
- Go 基本数据类型
- 4 组合类型的使用
- 5 数据结构
- 6 Go package 中不为人知的知识
- 7 反射和接口
- 8 Go UNIX 系统编程
- 08.1 关于 UNIX 进程
- 08.2 flag 包
- 8.2 flag 包
- 08.3 io.Reader 和 io.Writer 接口
- 08.4 bufio 包
- 08.5 读取文本文件
- 08.6 从文件中读取所需的数据量
- 08.7 为什么我们使用二进制格式
- 08.8 读取 CSV 文件
- 08.9 写入文件
- 08.10 从磁盘加载和保存数据
- 08.11 再看strings包
- 08.12 关于bytes包
- 08.13 文件权限
- 08.14 处理 Unix 信号
- 08.15 Unix 管道编程
- 08.16 遍历目录树
- 08.17 使用 ePBF
- 08.18 关于 syscall.PtraceRegs
- 08.19 跟踪系统调用
- 08.20 User ID 和 group ID
- 08.21 其他资源
- 08.22 练习
- 08.23 总结
- 9 并发 Goroutines、Channel 和 Pipeline
- 10 Go 并发-进阶讨论
- 11 代码测试、优化及分析
- 12 Go 网络编程基础
- 13 网络编程 - 构建服务器与客户端
04.7 计算Pi的精确值
在本小节中你将学习到如何使用Go标准库math/big
以及其提供的特殊类型,并计算高精度的Pi值。
本节的代码是我所见过的最丑陋的Go代码,甚至用Java写看起来都会好一些。
calculatePi.go
使用Bellard规则计算Pi值,代码将分4部分展示。
第一部分:
> package main
>
> import (
> "fmt"
> "math"
> "math/big"
> "os"
> "strconv"
> )
>
> var precision uint = 0
precision
变量代表你想得到的Pi值精度,其声明为全局变量保证在整个程序中都可以被访问到。
第二部分:
> func Pi(accuracy uint) *big.Float {
> k := 0
> pi := new(big.Float).SetPrec(precision).SetFloat64(0)
> k1k2k3 := new(big.Float).SetPrec(precision).SetFloat64(0)
> k4k5k6 := new(big.Float).SetPrec(precision).SetFloat64(0)
> temp := new(big.Float).SetPrec(precision).SetFloat64(0)
> minusOne := new(big.Float).SetPrec(precision).SetFloat64(-1)
> total := new(big.Float).SetPrec(precision).SetFloat64(0)
>
> two2Six := math.Pow(2, 6)
> two2SixBig := new(big.Float).SetPrec(precision).SetFloat64(two2Six)
new(big.Float)
创建一个big.Float
类型的变量,并调用SetPrec()
函数将精度设置为参数precision
。
第三部分是贝拉算法计算精确Pi值的函数Pi()
实现(关于贝拉算法可查看文末简介):
> for {
> if k > int(accuracy) {
> break
> }
> t1 := float64(float64(1) / float64(10*k+9))
> k1 := new(big.Float).SetPrec(precision).SetFloat64(t1)
> t2 := float64(float64(64) / float64(10*k+3))
> k2 := new(big.Float).SetPrec(precision).SetFloat64(t2)
> t3 := float64(float64(32) / float64(4*k+1))
> k3 := new(big.Float).SetPrec(precision).SetFloat64(t3)
> k1k2k3.Sub(k1, k2)
> k1k2k3.Sub(k1k2k3, k3)
>
> t4 := float64(float64(4) / float64(10*k+5))
> k4 := new(big.Float).SetPrec(precision).SetFloat64(t4)
> t5 := float64(float64(4) / float64(10*k+7))
> k5 := new(big.Float).SetPrec(precision).SetFloat64(t5)
> t6 := float64(float64(1) / float64(4*k+3))
> k6 := new(big.Float).SetPrec(precision).SetFloat64(t6)
> k4k5k6.Add(k4, k5)
> k4k5k6.Add(k4k5k6, k6)
> k4k5k6 = k4k5k6.Mul(k4k5k6, minusOne)
> temp.Add(k1k2k3, k4k5k6)
>
> k7temp := new(big.Int).Exp(big.NewInt(-1), big.NewInt(int64(k)), nil)
> k8temp := new(big.Int).Exp(big.NewInt(1024), big.NewInt(int64(k)), nil)
>
> k7 := new(big.Float).SetPrec(precision).SetFloat64(0)
> k7.SetInt(k7temp)
> k8 := new(big.Float).SetPrec(precision).SetFloat64(0)
> k8.SetInt(k8temp)
>
> t9 := float64(256) / float64(10*k+1)
> k9 := new(big.Float).SetPrec(precision).SetFloat64(t9)
> k9.Add(k9, temp)
> total.Mul(k9, k7)
> total.Quo(total, k8)
> pi.Add(pi, total)
>
> k = k + 1
> }
> pi.Quo(pi, two2SixBig)
> return pi
> }
这部分代码是贝拉算法的Go实现,你必须借助于math/big
包中特定的函数进行计算,因为这些函数能够实现你想要达到的数字精度,可以说如果不使用big.Float
、big.Int
变量以及math/big
中的函数,高精度的Pi值根本无法计算。
最后一部分代码:
> func main() {
> arguments := os.Args
> if len(arguments) == 1 {
> fmt.Println("Please provide one numeric argument!")
> os.Exit(1)
> }
>
> temp, _ := strconv.ParseUint(arguments[1], 10, 32)
> precision = uint(temp) * 3
>
> PI := Pi(precision)
> fmt.Println(PI)
> }
执行calculatePi.go
得到如下输出:
$ go run calculatePi.go
Please provide one numeric argument!
exit status 1
$ go run calculatePi.go 20
3.141592653589793258
$ go run calculatePi.go 200
3.141592653589793256960399361738762404019183156248573243493179283571046450248913467118511784317615354282017929416292809050813937875283435610586313363548602436768047706489838924381929
本节的代码需要使用很多不同的数据类型,务必保证数据类型的正确使用!
课外阅读
文中提到的贝拉算法简介:
Fabrice Bellard在圆周率算法方面也有着惊人的成就,1997年FabriceBellard提出最快圆周率算法公式。在计算圆周率的过程中,Fabrice Bellard使用改良后的查德诺夫斯基方程算法来进行圆周率的计算,并使用贝利-波温-劳夫算法来验证计算的结果。为了纪念他对圆周率算法所作出的杰出贡献,Fabrice Bellard所使用的改良型算法被命名为Fabrice Bellard算法,这种算法是目前所有圆周率算法中最快的一种,这个计算N位PI的公式比传统的BBQ算法要快47%。 2009年的最后一天,Fabr ice Bellard宣布另一重大突破:他用桌面电脑打破了由超级计算机保持的圆周率运算记录。这是一个壮举, 他将PI计算到了小数点后2.7万亿位!更令人惊讶的是, 他使用的不过是价格不到2000欧元的个人PC,仅用了116天,就计算出了PI的小数点后第2.7万亿位,超过了排名世界第47位的T2K Open超级计算机于2009年8月17日创造的世界纪录。新纪录比原纪录多出1200亿位,然而,他使用的这台桌面电脑的配置仅为:2.93GHz Core i7 CPU,6GB内存,7.5TB硬盘! 不过这次为了加快计算完成的速度保住排名第一的位置,Fabrice Bel lard使用了9台联网的电脑来对数据进行验证, 若使用一台电脑来验证计算结果的话, 则需要额外增加13天的计算时间。 Fabrice Bellard在圆周率方面的辉煌成就, 使他创造多次圆周率单一位计算的世界纪录(计算10的整次幂位) , 也曾因此而登上《科学美国人》法文版。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论