You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go测试(TDD):圆周长测试中got与预期值为何不一致?

浮点数精度导致Go测试失败的原因及解决方案

测试失败的核心原因

你的测试失败是浮点数精度差异导致的,具体细节:

  • math.Pi是float64类型(双精度浮点数),在Perimeter方法中,2 * math.Pi * c.radius的运算过程是:先将float32类型的radius转换为float64完成计算,再将结果转回float32返回。
  • 测试代码中的want是先计算2 * math.Pi * 5.0(全程float64运算),再将最终结果转换为float32。
    这两个路径的类型转换时机不同,导致最终的float32值出现微小的精度偏差(比如你看到的31.415928 vs 31.415926),直接用==比较就会判定为不相等。

关键注意事项与修复方案

1. 避免直接用==比较浮点数

浮点数在二进制存储和运算中天生存在精度限制,永远不要直接用相等运算符比较两个浮点数。正确的做法是判断两个值的差值绝对值是否小于一个可接受的容差(比如1e-6):

func TestCirclePerimeter(t *testing.T) {
    circle := Circle{5.0}
    got := circle.Perimeter()
    want := float32(2 * math.Pi * 5.0)

    // 用容差判断是否近似相等
    const tolerance = 1e-6
    if math.Abs(float64(got-want)) > tolerance {
        t.Errorf("got %g, want %g", got, want)
    }
}

2. 统一浮点数类型

尽量在代码中使用同一种浮点数类型,减少不必要的类型转换带来的精度损失。比如把Circle的radius改为float64:

// perimeter.go
type Circle struct {
    radius float64
}

func (c Circle) Perimeter() float64 {
    return 2 * math.Pi * c.radius
}

对应的测试代码也统一用float64:

// perimeter_test.go
func TestCirclePerimeter(t *testing.T) {
    circle := Circle{5.0}
    got := circle.Perimeter()
    want := 2 * math.Pi * 5.0 // 直接是float64,无需转换

    const tolerance = 1e-6
    if math.Abs(got-want) > tolerance {
        t.Errorf("got %g, want %g", got, want)
    }
}

3. 了解不同浮点数类型的精度

  • float32是单精度浮点数,仅能提供约6-7位有效数字,适合对精度要求不高的场景。
  • float64是双精度浮点数,能提供约15-17位有效数字,是Go中默认的浮点数类型,大多数场景下优先使用float64可以减少精度问题。

内容的提问来源于stack exchange,提问作者Ganglin Wu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 21:32:43