Fork me on GitHub

Go语言开发-布尔与数值类型-浮点类型

2.3.2.浮点类型

Go语言提供了两种类型的浮点数和两种类型的复数,它们的名字及取值范围如表2.7所示。Go语言中的浮点数广泛使用IEEE-754格式表示(http://en.wikipedia.org/wiki/IEEE_754-2008)。该格式也是很多微型处理器和浮点数单元所使用的原生格式,所以在大多数情况下Go语言能够直接利用硬件的浮点数支持。

表2.7 Go语言的浮点类型:

float32\(±3.40282346638528859811704183484516925440*10^{38}\)尾数部分计算精度大概是7个十进制数
float64\(±1.797693134862315708145274237317043567981*10^{308}\)尾数部分计算精度大概是巧个十进制数
complex64实部和虚部都是float32类型
complex128complex128实部和虚部都是float64类型

Go语言的浮点数支持表2.4中所列出的所有算术运算。math包中的大多数常量和所有函数在表2.8,表2.9和表2.10中列出。

浮点数使用小数点或者指数的形式来表示,例如0.0、3.、8.2、-7.4、-6e4、.1、5.9E-3。计算机内部通常使用二进制表示浮点数,这意味着有些小数可以被精确地表示(如 0.5),但是其他的浮点数就只能近似表示(如0.1和0.2)。此外,使用固定长度位数来表示的数值,其所能表示出的数据大小是有限制的。这不是Go语言特有的问题,而是所有主流语言都具有的问题。然而,这种不精确性并不是总都是显而易见的,因为Go语言使用智能算法来输出浮点数,在保证精度的前提下使用尽可能少的位数。

表2.8 math包中的常量和函数    #1

除非特别说明,math包中的所有函数都接受并返回float64类型数值。所有给出的常量都被截断至至多包含15位小数以更好地适应表。

math.Abs(x)|x|,即x的绝对值
math.Acos(x)以弧度为单位的x的反余弦值
math.Acosh(x)以弧度为单位的x的反双曲余弦值
math.Asin(x)以弧度为单位的x的反正弦值
math.Asinh(x)以弧度为单位的x的反双曲正弦值
math.Atan(x)以弧度为单位的x的反正切值
math.Atan2(y, x)以弧度为单位的\(y/x\)的反正切值
math.Atanh(x)以弧度为单位的x的反双曲正切值
math.Cbrt(x)\(∛x\),即x的开立方根
math.Ceil(x)\(⌈x⌉\),即大于等于x的最小整数值;如math.Ceil(5.4)==6.0
math.Copysign(x,y)与x的值相同且与y的符号位相同的值
math.Cos(x)以弧度为单位的x的余弦值
math.Cosh(x)以弧度为单位的x的双曲余弦值
math.Dim(x,y)实际上,等价于math.Max(x-y,0.0)
math.E常量e;约等于2.718281828459045
math.Erf(x)erf(x),x的高斯误差函数
math.Erfc(x)erfc(x),即x的互补高斯误差函数
math.Exp(x) \(e^x\)
math.Exp2(x) \(2^x\)
math.Expml(x) \(e^x-1\),但当x接近于0时,其精度优于使用math.Exp(x)-1
math.Float32bits(f)f的IEEE-754二进制表示形式,可将其视为uint32类型
math.Float32frombits(u)以IEEE-754标准表示的float32类型
math.Float64bits(x)x的IEEE-754二进制表示形式,可将其视为uint64类型
math.Float64frombits(u)以IEEE-754标准表示的float64类型

表2.9 math包中的常量和函数    #2

math.Floor(x)\(⌊x⌋\),即小于等于x的最大整数,如math.Floor(5.4)==5.0
math.Frexp(x)有float64类型的frac和int类型的exp使得 成立,其反函数是math.Ldexp()
math.Gamma(x)Γ(x), 即 (x − 1)!
math.Hypot(x, y)math.Sqrt(x * x, y * y)
math.Ilogb(x)以2为底的x的幂,对其结果取整,参见math.Logb()
math.Inf(n)如果int n>=0,则其结果为float64类型的+ ,否则其结果为-
math.IsInf(x, n)如果x是float64类型的+ 且int n>0,或者x=- 且n<0,或者x是- 和+ 中的任何一个且n=0,则其结果为true,否则为false。
math.IsNaN(x)如果x是IEEE-754标准中的“NaN”值,则其结果为true
math.J0(x)\(J_0 (x)\),第一类贝塞尔函数
math.J1(x)\(J_1 (x)\),第一类贝塞尔函数
math.Jn(n,x)\(J_n (x)\),n阶的(n的类型为int)第一类贝塞尔函数
math.Ldexp(x, n)\(x×2^n\),其中x的类型为float64类型且n的类型为int,其反函数为math.Frexp()
math.Lgamma(x)\(log_e⁡(Γ(x))\)
math.Ln2\(log_e⁡(2)\),约等于0.693 147 180559945
math.Ln10\(log_e⁡(10)\),约等于2.302 585 092 994 045
math.Log(x)\(log_e⁡(x)\)
math.Log2E\(1/log_e⁡(2)\),约等于1.442 695 021 629333
math.Log10(x)\(log_{10} ⁡(x)\)
math.Log10E\(1/log_e⁡(10)\),约等于0.434 294 492 006301
math.Log1p(x)\(log_e⁡(1+x)\),当x接近0时,其结果的精度优于使用math.log()
math.Log2(x)\(log_2⁡(x)\)
math.Logb(x)x的二进制幂,参见math.Ilogb()
math.Max(x, y)x,y中较大的值
math.Min(x, y)x,y中较小的值
math.Mod(x, y)\(x/y\)的余数,参见math.Remainder()

2.10 math包中的常量和函数 #3

math.Modf(x)其结果为一个float64类型的整数和一个float64类型的小数
math.NaN(x)IEEE-754表示的NaN值
math.Nextafter( x, y)其结果为x向y的下一个可表达的值
math.Pi常量π,约等于3.141 592 653 589793
math.Phi常量 φ,约等于1.618 033 988749984
math.Pow(x, y)\(x^y\)
math.Pow10(n)其结果为float64类型的\(10^n\),其中x的类型为int
math.Remainder( x, y)与IEEE-754兼容的\(x/y\)的余数,参见math.Mod()
math.Signbit(x)其结果为bool类型,如果x为负数(包括-0.0)则结果为true
math.Sin(x)以弧度为单位的x的正弦值
math.SinCos(x)以弧度为单位的x的正弦值和余弦值
math.Sinh(x)以弧度为单位的x的双曲正弦值
math.Sqrt(x)\(√x\)
math.Sqrt2\(√2\),约等于1.414 213 562 373 095
math.SqrtE\(√e\),约等于1.648 721 270700128
math.SqrtPi\(√π\),约等于1.772 453 850905 516
math.SqrtPhi\(√ϕ\),约等于1.272 019649514 068
math.Tan(x)以弧度为单位的x的正切值
math.Tanh(x)以弧度为单位的x的双曲正切值
math.Trunc(x)将x的小数部分设置为0
math.Y0(x)\(Y_0(x)\),第二类贝塞尔函数
math.Y1(x)\(Y_1(x)\),第二类贝塞尔函数
math.Yn(n, x)\(Y_n(x)\),n阶第二类贝塞尔函数

表2.3中列出的所有比较操作都可以用于浮点数。但不幸的是,由于浮点数表示的是近似值,对它们进行相等或不等比较时并不总能按预期的那样工作。

 

这里我们定义了两个初始值为0的float64类型的浮点数,我们为第一个值加上10个0.1,为第二个值加上5个0.2,所以结果应该都是1。然而,正如代码片段下面给出的输出所示,有些浮点数的精度并不如预期的那样。由此可见,使用==或者!=来比较浮点数时,我们应该加倍小心。当然,有些情况下比较明智的做法是使用内置的操作符来比较浮点数,例如,可以使用if y != 0.0 { return x / y }方法来避免除数为0。

“%-5t”格式以向左对齐的5个字符宽的区域打印bool值。

EqualFloat() 函数以给定的精度比较两个float64浮点数,如果将一个负数作为limit参数传递给该函数,则将该精度设为机器所能达到的最大精度。它依赖于标准库math包中的函数 (和一个常量)。

另一种替代(速度较慢)的方法是将数字作为字符串进行比较。

对于上面的函数,其精度以小数点后面数字的位数指定。fmt.sprintf()函数的%格式化参数接受一个*号占位符,并要求用一个数字替换之,所以在这里我们基于给定的float64类型创建了两个字符串,并使用给定的小数位数进行格式化。如果给定的数值位数不一样,那么字符串a和b的长度也不一样(如,12·32和592·85),这样我们就能执行一个快速的短路相等测试。

在大多数情况下,如果需要浮点数,float64 类型是最好的选择,因为math包中的所有函数 都是使用float64的。然而,Go语言也提供了float32 类型,当内存有限且不需要使用math包,或者愿意忍受在float64与其它类型之间进行进行必要的转换时的不便时,float32 类型是非常有用的。因为Go语言的浮点类型是固定长度的,因此从外部文件或者网络中读写数据是非常安全的。

使用标准的Go语法(如int(float))可以将浮点数转换为整数,但在这种情况下小数部分会被丢弃。当然,如果浮点数的值超出了要转换的整型的范围,由此产生的结果值将是不可预期的。我们可以使用一个安全转换函数来解决这个问题。例如:

Go语言规范(golang.org/doc/go_spec.html)中规定int与uint型占用相同的位数且uint总是32位或者64位的。这意味着int型至少是32位的,我们可以安全地使用math.MinInt32和math.MaxInt32常量来作为int的最大和最小值。

我们使用math.Modf()函数来分隔给定数值(都是float64型)的整数和小数部分,而不是简单地返回整数部分(即截断),如果小数部分≥ 0.5,则根据四舍五入取整。

与我们在自定义函数Uint8FromInt()中所做的不同的是,我们不是返回一个error值,而是当值越界时终止程序运行,所以我们使用了内置的panic() 函数,它会导致运行时异常并终止程序运行,除非调用recover()函数捕获该异常。这意味着如果该程序成功运行,我们就知道转换过程没有值越界情况发生。(还要注意的是该函数并没有以return语句结束,因为Go编译器足够智能可以意识到调用panic()时的不会有正常的返回值。)

2.3.2.1.复数类型

Go语言支持两种复数类型,参见表2.7。我们可以使用内置的 complex() 函数或使用含虚数的常量来创建复数。复数的各部分可以通过使用内置的real() 或imag()函数来获得,这两个函数都是返回float64了类型的数值(对于complex64类型返回float32)。

复数支持表2.4中所有的算术运算。所有的比较操作符中只有==和!= 可用于复数(参见表2.3),但也会遇到与比较浮点数时相同的问题。标准库中有一个复数包math/cmplx,参见表2.11。

请看下面的例子:

和数学中的用法一样,Go语言也使用后缀i表示虚数。上例中,x和z都是complex128类型,所以它们的实部和虚部都是float64类型;y是complex64类型的,所以它的实部和虚部都是float32类型的。需要注意的一点是,这里使用了complex64类型名(或任何其它内置的类型名)作为函数来执行类型转换。所以这里复数-18.3+8.9i(根据复数常量推断其类型为complex128)被转换为complex64类型。然而complex()是一个函数,其接受两个float类型并返回相应的complex128类型的数值。

表2.11 math/Complex包中的函数

导入”math/cmplx”,除非特别说明,否则所有函数都接收并返回complex128类型的值

cmplx.Abs(x)|x|,即float64类型的x的绝对值
cmplx.Acos(x)以弧度为单位的x的反余弦值
cmplx.Acosh(x)以弧度为单位的x的反双曲余弦值
cmplx.Asin(x)以弧度为单位的x的反正弦值
cmplx.Asinh(x)以弧度为单位的x的反双曲正弦值
cmplx.Atan(x)以弧度为单位的x的反正切值
cmplx.Atanh(x)以弧度为单位的x的反双曲正切值
cmplx.Conj(x)x的复共轭
cmplx.Cos(x)以弧度为单位的x的余弦值
cmplx.Cosh(x)以弧度为单位的x的双曲余弦值
cmplx.Cot(x)以弧度为单位的x的余切
cmplx.Exp(x)\(e^x\)
cmplx.Inf()复数(math.Inf(1),math.Inf(1))
cmplx.IsInf(x)如果real(x) 或 imag(x) 的值是±∞,则返回true,否则返回false
cmplx.IsNaN(x)如果real(x) 或 imag(x)是“不是数字”且都不是±∞,则返回true,否则返回false
cmplx.Log(x)\(log_e⁡x\)
cmplx.Log10(x)\(log_{10}⁡x\)
cmplx.NaN()非数字的复数值
cmplx.Ph ase(x)值在[−π, +π]范围内的float64类型的x的相位
cmplx.Polar(x)float64类型的r的绝对值和θ满足 ;θ在[−π, +π]范围内
cmplx.Pow(x, y)\(x^y\)
cmplx.Rect(r, θ)float64类型的极坐标r和θ生成的complex128值
cmplx.Sin(x)以弧度为单位的x的正弦值
cmplx.Sinh(x)以弧度为单位的x的双曲正弦值
cmplx.Sqrt(x)\(√x\)
cmplx.Tan(x)以弧度为单位的x的正切值
cmplx.Tanh(x)以弧度为单位的x的双曲正切值

需要注意的一点是,fmt.Println()函数可以打印不拘泥于特定格式的复数。

一般可以使用的最佳的复数类型是complex128,因为math/cmplx包中的所有函数都是使用的complex128类型。然而,Go也提供了complex64 类型,这在内存有限的情况下是非常有用的。因为Go语言的复数类型是固定长度的,所以从外部如文件或网络连接中读写它们总是安全的。

在本章中我们讲授了Go语言的布尔类型和数值类型,并在表格中给出了可用的操作符和函数。下一章我们将讲授Go语言的字符串类型,包括Go语言的格式化打印功能,当然,也包括对布尔值和数值的格式化打印功能。在结束本章之前,我们会讲解一个短小但完整的示例程序作为对本章知识的回顾。


目录


作者:Johnson
原创文章,版权所有,转载请保留原文链接。

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注