当前位置: 首页 > news >正文

GO语言入门:常用数学函数2

14.6 大型数值

math/big 包中公开了一些实用 API,用于表示大型整数值和浮点数值。当基础类型无法容纳要使用的数值时,应改用 big 包中提供的新类型。例如 Int、Float 等。

14.6.1 大型整数值之间的运算

若希望让下面两个整数值完成加、减法运算,这样编写代码会发生错误。

var (a uint64 = 8000006554217002143024b uint64 = 6676225236988563328930
)
c1 := a + b
c2 := a - b
fmt.Printf("%d + %d = %d\n", a, b, c1)
fmt.Printf("%d - %d = %d\n", a, b, c2)

运行程序会得到如下的错误信息:

constant 8000006554217002143024 overflows uint64
constant 6676225236988563328930 overflows uint64

原因是数值太大,已经超过uint64类型的有效范围。

解决方案只能使用 big 包中的 Int 类型。下面的代码将重新实现上述两个整数进行加、减运算的功能。

// 两个整数值的字符串形式
var (num1 = "8000006554217002143024"num2 = "6676225236988563328930"
)
// 实例化 Int 对象,使用指针类型(*Int)
var bigInt1 = new(big.Int)
var bigInt2 = new(big.Int)
// 将两个字符串表示的值设置到 Int 对象中
bigInt1.SetString(num1, 10)
bigInt2.SetString(num2, 10)
// 进行加法运算
var res1 = new(big.Int)
res1.Add(bigInt1, bigInt2)
fmt.Printf("%d + %d = %d\n", bigInt1, bigInt2, res1)
// 进行减法运算
var res2 = new(big.Int)
res2.Sub(bigInt1, bigInt2)
fmt.Printf("%d - %d = %d\n", bigInt1, bigInt2, res2)

由于基础的整数类型(例如 int64、uint64)均无法容纳两个大型整数值,所以只能用字符串来表示。

num1 = "8000006554217002143024"
num2 = "6676225236988563328930"

然后,调用 Int 实例的 SetString 方法将整数值设置到 Int 实例中。如果要设置的值未超出基础类型的有效范围,是可以使用 SetInt64 SetUint64 方法的。

两个大型整数值进行加减运算后,其结果也是大型数值,因此也需要使用 Int 对象来存储计算结果。加法运算调用 Add 方法,减法运算调用Sub方法。

res1.Add(bigInt1, bigInt2)
res2.Sub(bigInt1, bigInt2)

运行上述程序,将得到以下计算结果:

8000006554217002143024 + 6676225236988563328930 = 14676231791205565471954
8000006554217002143024 - 6676225236988563328930 = 1323781317228438814094

big 包中的类型对象一般会使用指针类型(如 *Int、 *Float 等)。一方面,指针类型仅引用对象的地址,保证在调用各种方法(如上面用到的 Add 方法)过程中所传递的都是唯一的实例;另一方面,这些类型实例存储的数值很大,占用内存空间也比较多,不适宜频繁复制(非指针类型变量在赋值时会复制对象,而指针类型变量仅复制对象的内存地址)。

14.6.2 阶乘运算

阶乘的计算结果往往较大,极有可能超出基础整数类型的范围,因此使用big.Int类型来存储阶乘运算的结果较为合适。

big.Int 类型是可以直接进行阶乘运算的,因为它有一个名为 MulRange 的方法,其签名如下:

func MulRange(a int64, b int64) *Int

它的功能是产生[a, b]范围内的所有整数的积(包含 a 和 b)。运用这个方法便可以轻松完成阶乘运算,即将求积的整数范围设定在 [1, n] [2, n]。例如,要求 5 的阶乘,可以这样调用方法:

MulRange(1, 5)
或者
MulRange(2, 5)

下面的示例分别求 30 和 50 的阶乘。

var c = new(big.Int)
// 求 30 的阶乘
c.MulRange(1, 30)
fmt.Printf("30! = %d\n", c)
// 求 50 的阶乘
c.MulRange(1, 50)
fmt.Printf("50! = %d\n", c)

计算结果如下:

30! = 265252859812191058636308480000000
50! = 304140932017133780436126081660647688443776415689605120000000000000

14.6.3 使用大型浮点数值

big 包中的 Float 类型与 Int 类型相似,专用于存储大型的浮点数值。

下面的代码将创建 Float 对象,并设置一个大型的浮点数值。

var strfloat = "0.001234567890234567893456789"
var bigFloat = new(big.Float)
// 设置精度
bigFloat.SetPrec(50)
// 设置浮点数值
bigFloat.SetString(strfloat)
// 打印到屏幕上
fmt.Printf("%.50f\n", bigFloat)

SetPrec 方法用来设置浮点数值的精度,上述代码中设置为 50。随后调用 SetString 方法将字符串表示的浮点数设置到 Float 对象中。

浮点数值打印结果如下:

0.00123456789023456726950289663591320277191698551178

由于二进制运算存在误差,打印出来的数值与原值会有差异。

Float 结构体还定义了一些可进行常见运算的方法。例如,Add 方法支持加法运算,Sub 方法支持减法运算。

下面的示例将演示大型浮点数值的四则运算。

步骤 1:定义两个 float64 类型的变量,作为 Float 对象的原始数值。

var (a float64 = 1550.797220660354896132160489549963189232654585896489465456159657b float64 = 0.0016200166894105953690156
)

步骤 2:创建三个 Float 对象实例。

var (bigFa = new(big.Float)bigFb = new(big.Float)bigRes = new(big.Float) // 存放计算结果
)

步骤 3:设置精度。

bigFa.SetPrec(100)
bigFb.SetPrec(100)
bigRes.SetPrec(100)

步骤 4:设置原始数值。

bigFa.SetFloat64(a)
bigFb.SetFloat64(b)

如果数值很大,超过了float64类型的可容纳范围,则可以使用字符串来表示数值,再调用 SetString 方法来设置。

步骤 5:完成四则运算。

// 加
bigRes.Add(bigFa, bigFb)
fmt.Printf("%.15f + %.15f = %.15f\n", bigFa, bigFb, bigRes)// 减
bigRes.Sub(bigFa, bigFb)
fmt.Printf("%.15f - %.15f = %.15f\n", bigFa, bigFb, bigRes)// 乘
bigRes.Mul(bigFa, bigFb)
fmt.Printf("%.15f * %.15f = %.15f\n", bigFa, bigFb, bigRes)// 除
bigRes.Quo(bigFa, bigFb)
fmt.Printf("%.15f / %.15f = %.15f\n", bigFa, bigFb, bigRes)

步骤 6:运行示例,结果如下所示:

1550.797220660354924 + 0.001620016689411 = 1550.798840677044334
1550.797220660354924 - 0.001620016689411 = 1550.795600643665513
1550.797220660354924 * 0.001620016689411 = 2.512317379361341
1550.797220660354924 / 0.001620016689411 = 957272.373054734186086

相关文章:

  • TCVectorDB 向量数据库简介
  • K8s-Pod详解
  • 操作系统是如何运行的?
  • 2014-2021年 区域经济高质量发展-高质量需求指标数据
  • 【Hot100】 240. 搜索二维矩阵 II
  • 微信小程序中使用h5页面预览图片、视频、pdf文件
  • 软考复习——知识点软件开发
  • 深入理解Java包装类:自动装箱拆箱与缓存池机制
  • Linux操作系统--进程的创建和终止
  • 缓存 --- Redis的三种高可用模式
  • 重构之去除多余的if-else
  • Kubernetes相关的名词解释Dashboard界面(6)
  • 年化26.9%的稳健策略|polars重构因子计算引擎(python策略下载)
  • 03【变量观】`let`, `mut` 与 Shadowing:理解 Rust 的变量绑定哲学
  • c++STL——list的使用和模拟实现
  • go环境安装mac
  • 02【初体验】安装、配置与 Hello Cargo:踏出 Rust 开发第一步
  • Three.js + React 实战系列-3D 个人主页 :完成 Navbar 导航栏组件
  • Mac-VScode-C++环境配置
  • Git拉分支技巧:从零开始创建并推送分支
  • 两岸基层民生发展交流会在浙江开幕
  • 一镇一链、一园一策,上海闵行发布重点产业区镇协同产业地图
  • 昆明盘龙区一火灾调查报告公布:老人火盆取暖引燃房屋致身亡
  • 何立峰会见美国英伟达公司总裁黄仁勋:欢迎美资企业深耕中国市场
  • 碳访|储能行业将迎市场化考验,宁德时代:我们希望“卷价值”
  • 黄山景区成功搜救一名“野游”游客,当事人受处罚并付救援费