Go 语言数据类型与精度详解
基本数据类型
1. 整数类型
有符号整数
go
var a int8 // 1字节,范围:-128 到 127
var b int16 // 2字节,范围:-32768 到 32767
var c int32 // 4字节,范围:-2147483648 到 2147483647
var d int64 // 8字节,范围:-9223372036854775808 到 9223372036854775807
var e int // 平台相关,32位系统为int32,64位系统为int64
无符号整数
go
var a uint8 // 1字节,范围:0 到 255
var b uint16 // 2字节,范围:0 到 65535
var c uint32 // 4字节,范围:0 到 4294967295
var d uint64 // 8字节,范围:0 到 18446744073709551615
var e uint // 平台相关
var f byte // uint8 的别名
var g rune // int32 的别名,表示Unicode码点
2. 浮点数类型
go
var a float32 // 4字节,单精度浮点数
var b float64 // 8字节,双精度浮点数(默认类型)
var c complex64 // 8字节,复数,实部和虚部都是float32
var d complex128 // 16字节,复数,实部和虚部都是float64
3. 布尔类型
go
var a bool = true
var b bool = false
4. 字符串类型
go
var s string = "Hello, World!"
精度
整数精度
go
package main
import (
"fmt"
"math"
"unsafe"
)
func main() {
// 整数类型的精度和范围
fmt.Printf("int8 范围: %d 到 %d\n", math.MinInt8, math.MaxInt8)
fmt.Printf("int16 范围: %d 到 %d\n", math.MinInt16, math.MaxInt16)
fmt.Printf("int32 范围: %d 到 %d\n", math.MinInt32, math.MaxInt32)
fmt.Printf("int64 范围: %d 到 %d\n", math.MinInt64, math.MaxInt64)
fmt.Printf("uint8 范围: 0 到 %d\n", math.MaxUint8)
fmt.Printf("uint16 范围: 0 到 %d\n", math.MaxUint16)
fmt.Printf("uint32 范围: 0 到 %d\n", math.MaxUint32)
fmt.Printf("uint64 范围: 0 到 %d\n", uint64(math.MaxUint64))
// 大小验证
var i int
fmt.Printf("int 大小: %d 字节\n", unsafe.Sizeof(i))
}
浮点数精度
go
package main
import (
"fmt"
"math"
)
func floatPrecisionDemo() {
// float32 精度(约6-7位十进制数)
var f32 float32 = 123.456789
fmt.Printf("float32 值: %.10f\n", f32) // 输出: 123.4567871094
// float64 精度(约15-16位十进制数)
var f64 float64 = 123.4567890123456789
fmt.Printf("float64 值: %.20f\n", f64) // 输出: 123.4567890123456800
// 精度测试
fmt.Printf("float32 最大正数: %e\n", math.MaxFloat32)
fmt.Printf("float64 最大正数: %e\n", math.MaxFloat64)
fmt.Printf("float32 最小正数: %e\n", math.SmallestNonzeroFloat32)
fmt.Printf("float64 最小正数: %e\n", math.SmallestNonzeroFloat64)
// 浮点数比较(由于精度问题,不要直接比较)
a := 0.1
b := 0.2
c := 0.3
// 错误的比较方式
fmt.Printf("直接比较: %v\n", a+b == c) // 可能输出 false
// 正确的比较方式
fmt.Printf("容差比较: %v\n", math.Abs((a+b)-c) < 1e-9) // 输出 true
}
复数精度
go
func complexPrecisionDemo() {
// complex64 精度
var c1 complex64 = 1.23456789 + 9.87654321i
fmt.Printf("complex64: %.10f + %.10fi\n", real(c1), imag(c1))
// complex128 精度
var c2 complex128 = 1.2345678901234567 + 9.8765432109876543i
fmt.Printf("complex128: %.20f + %.20fi\n", real(c2), imag(c2))
}
类型转换与精度损失
显式类型转换
go
package main
import "fmt"
func typeConversionDemo() {
// 整数类型转换
var big int64 = 1234567890
var small int32 = int32(big) // 显式转换
// 可能导致精度损失的情况
var tooBig int64 = 9999999999
var converted int32 = int32(tooBig) // 溢出,值会改变
fmt.Printf("原始值: %d, 转换后: %d\n", tooBig, converted)
// 浮点数转整数(截断小数部分)
var f float64 = 123.987
var i int = int(f) // 123,小数部分被截断
fmt.Printf("浮点数: %f, 转整数: %d\n", f, i)
// 整数转浮点数
var num int = 123456789
var f32 float32 = float32(num)
var f64 float64 = float64(num)
fmt.Printf("整数: %d, float32: %f, float64: %f\n", num, f32, f64)
}
精度损失示例
go
func precisionLossDemo() {
// float32 到 float64 转换
f32 := float32(1.23456789)
f64 := float64(f32)
fmt.Printf("原始 float32: %.8f\n", f32)
fmt.Printf("转换到 float64: %.8f\n", f64)
// 大整数转浮点数的精度损失
bigInt := int64(9007199254740993) // 2^53 + 1
bigFloat := float64(bigInt)
fmt.Printf("大整数: %d\n", bigInt)
fmt.Printf("转浮点数: %.0f\n", bigFloat)
fmt.Printf("是否相等: %v\n", int64(bigFloat) == bigInt)
}
精度考虑
-
选择合适的数据类型:
- 一般情况使用
int
和float64
- 内存敏感场景使用特定大小的类型
- 金融计算考虑使用整数或
math/big
包
- 一般情况使用
-
避免隐式类型转换:
- Go 要求显式类型转换,这有助于避免意外行为
-
注意溢出和精度损失:
- 在类型转换时检查可能的溢出
- 浮点数比较使用容差而非直接相等
-
使用标准库函数:
goimport "math" // 安全的浮点数比较 func almostEqual(a, b, tolerance float64) bool { return math.Abs(a-b) < tolerance }
金融计算
go
package main
import (
"fmt"
"math/big"
)
func financialCalculation() {
// 对于金融计算,使用整数表示最小单位(如分)
type Money int64 // 以分为单位
var price Money = 1999 // 19.99元
var quantity int = 3
total := price * Money(quantity)
fmt.Printf("总价: %.2f 元\n", float64(total)/100.0)
// 或者使用 big.Rat 进行精确计算
priceRat := big.NewRat(1999, 100) // 19.99
quantityRat := big.NewRat(3, 1)
totalRat := new(big.Rat).Mul(priceRat, quantityRat)
fmt.Printf("精确总价: %s 元\n", totalRat.FloatString(2))
}
科学计算
go
func scientificCalculation() {
// 对于需要高精度的科学计算
const preciseValue float64 = 3.14159265358979323846
// 使用 float64 获得更高精度
circumference := 2 * preciseValue * 10.0
area := preciseValue * 10.0 * 10.0
fmt.Printf("周长: %.15f\n", circumference)
fmt.Printf("面积: %.15f\n", area)
// 避免累积误差
var sum float64
for i := 0; i < 1000; i++ {
sum += 0.1
}
fmt.Printf("累加 1000 次 0.1: %f\n", sum) // 不是精确的 100.0
fmt.Printf("误差: %e\n", sum-100.0)
}