清水泥沙

golang基础(10.浮点型与复数类型)

浮点型也叫做浮点数,用于表示包含小数点的数据,比如3.14,1.00

浮点数表示

在go中浮点数定义了两种类型,分别是float32float64,其中float32是单精度,精确到小数点后面7位数。float64为双精度(double),精确到小数点后15位。在实际开发中,应该尽可能地使用 float64 类型,因为 math 包中所有有关数学运算的函数都会要求接收这个类型。

var a float32 = 0.1
var b float64 = 0.2
c := 8.0 //需要加小数点,否则会自动推导为整

:::tips 浮点数的运算和整型一样,也要保证操作数的类型一致,float32 和 float64 类型数据不能混合运算,需要手动进行强制转化才可以 :::

浮点数的精度问题

浮点数不是一个精确的表达,因为二进制无法表达所有十进制小数,在双精度的时候会存在精度丢失问题。

package main

import "fmt"

func main() {
	var a float64= 0.7
	var b float64 = 0.1
	c := a + b
	fmt.Printf("a+b=%v 
", c) // 输出0.7999999999999999
	fmt.Printf("0.8 == 0.1+0.7 ? %v", (0.8 == a+b)) // 输出false
}

浮点数运算

浮点数可以通过算术运算符四则运算加减乘除,也可以进行比较运算(两个值得类型相等)。但在进行相等比较时,看起来相等的两个十进制浮点数,在底层转化为二进制时会丢失精度,因此不能被表象蒙蔽。如果需要比较可以使用以下方案。

package main

import (
	"fmt"
	"math"
)

func main() {
	var a float64 = 0.7
	var b float64 = 0.1
	c := a + b
	fmt.Printf("a+b=%v 
", c)                      // 输出0.7999999999999999
	fmt.Printf("0.8 == 0.1+0.7 ? %v", (0.8 == a+b)) // 输出false
	var p float64 = 0.00001
	if math.Dim(0.8, c) < p {
		fmt.Printf("两个偏差小于0.0001,相等")
	}
}

复数类型

除了整型和浮点型之外,Go 语言还支持复数类型,与复数相对,我们可以把整型和浮点型这种日常比较常见的数字称为实数,复数是实数的延伸,可以通过两个实数(在计算机中用浮点数表示)构成,一个表示实部(real),一个表示虚部(imag),常见的表达形式如下:

z = a + bi

其中 a、b 均为实数,i 称为虚数单位,当 b = 0 时,z 就是常见的实数,当 a = 0 而 b ≠ 0 时,将 z 称之为纯虚数,如果你理解数学概念中的复数概念,这些都很好理解,下面我们来看下复数在 Go 语言中的表示和使用。在 Go 语言中,复数支持两种类型:complex64(32位实部和虚部) 和 complex128(64位实部与虚部),对应的表示示例如下,和数学概念中的复数表示形式一致:

var complex_value_1 complex64        

complex_value_1 = 1.10 + 10i          // 由两个 float32 实数构成的复数类型
complex_value_2 := 1.10 + 10i         // 和浮点型一样,默认自动推导的实数类型是 float64,所以 complex_value_2 是 complex128 类型
complex_value_3 := complex(1.10, 10)  // 与 complex_value_2 等价

对于一个复数 z = complex(x, y),就可以通过 Go 语言内置函数 real(z) 获得该复数的实部,也就是 x,通过 imag(z) 获得该复数的虚部,也就是 y。复数支持和其它数字类型一样的算术运算符。当你使用 == 或者 != 对复数进行比较运算时,由于构成复数的实数部分也是浮点型,需要注意对精度的把握。更多关于复数的函数,请查阅 math/cmplx 标准库的文档。如果你对内存的要求不是特别高,最好使用 complex128 作为计算类型,因为相关函数大都使用这个类型的参数。