【Go】--数据类型

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)
}

精度考虑

  1. 选择合适的数据类型

    • 一般情况使用 intfloat64
    • 内存敏感场景使用特定大小的类型
    • 金融计算考虑使用整数或 math/big
  2. 避免隐式类型转换

    • Go 要求显式类型转换,这有助于避免意外行为
  3. 注意溢出和精度损失

    • 在类型转换时检查可能的溢出
    • 浮点数比较使用容差而非直接相等
  4. 使用标准库函数

    go 复制代码
    import "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)
}
相关推荐
h7997102 小时前
redis lua脚本(go)调用教程以及debug调试
redis·golang·lua
趣味编程1112 小时前
go的学习2---》并发编程
学习·golang·perl
桦说编程2 小时前
线程池拒绝策略避坑:谨慎使用抛弃策略,可能导致系统卡死
java·后端
星秀日3 小时前
框架--MyBatis
java·开发语言·mybatis
沐知全栈开发3 小时前
Ruby 条件判断
开发语言
BingoGo3 小时前
PHP 15 个高效开发的小技巧
后端·php
锥栗3 小时前
【Redis】【缓存】理解缓存三大问题:缓存穿透、缓存击穿与缓存雪崩及解决方案
java·后端·面试
_码力全开_3 小时前
JavaScript从入门到实战 (1):JS 入门第一步:它是什么?能做什么?环境怎么搭?
开发语言·前端·javascript·新人首发
9号达人3 小时前
泛型+函数式:让策略模式不再是复制粘贴地狱
java·后端·面试