【问题标题】:Map key of float type浮点型映射键
【发布时间】:2020-06-13 22:03:37
【问题描述】:

我有一个这样的结构类型:

type Vertex struct {
    X, Y, Z float32
}

我打算用Vertex 类型的键创建一个地图:

var vertices map[Vertex]struct{}

问题是 Go 会尝试将 float32 与 ==!= 进行比较,这 适合 float32。相反,我更喜欢与epsilon 进行近似比较。

我研究过this post,但是我不知道如何实现它,因为我的密钥struct有3个字段。任何人都可以帮我使用我的结构作为映射键吗?谢谢。

【问题讨论】:

  • 请注意,近似比较不具有传递性,不能真正用于地图。如果您以足够近的间隔比较它们,那么您所有的键都是相等的。
  • 找到另一种生成密钥浮点近似值的方法会根据执行的操作产生不同的结果,根据您获得它的方式,0.1 可能是 2 个不同的值;一种不推荐的方法是明确地将浮点值存储到字符串中的小数点后 n 位,并在可行的情况下使用它。
  • 如果内置 == 不适合您的目的,您不能使用 Go map。真的就是这么简单。

标签: go


【解决方案1】:

想法

受@ShubhamSrivastava 评论的启发,想法是:

  • float32 坐标将四舍五入到特定的小数点

基本原理

由于精确的 ==!= 比较(映射键要求)不适用于浮点数,因此当 float32 始终四舍五入到有限的小数点时,此类比较更有意义。

实施

我通过这些方法将 Vertex 类型内的 float32 字段舍入到特定小数点

// round floating point fields of my type to a specific decimal point
func vertRoundTo(vi Vertex, decimals uint32) (vo Vertex, err error) {
    if vo.X, err = roundTo(vi.X, decimals); err != nil {
        return Vertex{}, err
    }
    if vo.Y, err = roundTo(vi.Y, decimals); err != nil {
        return Vertex{}, err
    }
    if vo.Z, err = roundTo(vi.Z, decimals); err != nil {
        return Vertex{}, err
    }
    return
}

// round float32 to a specific decimal point
// https://stackoverflow.com/a/52048478/3405291
func roundTo(fi float32, decimals uint32) (fo float32, err error) {
    if decimals < 1 {
        err = errors.New("minimum decimal point is exceeded")
        return
    }
    fo = float32(math.Round(float64(fi)*float64(decimals)) / float64(decimals))
    return
}

我使用上面的方法是这样的:

// "cluster" is already filled with rounded floats
func (c *cluster) DoesClusterContainVertex(v Vertex) (does bool, err error) {
    // coordinates would be rounded to a specific decimal point
    // since exact == and != comparison is NOT proper for float
    // such comparisons are required for map key
    var vRound Vertex
    if vRound, err = vertRoundTo(v, 4); err != nil {
        return
    }
    if _, ok := c.verts[vRound]; ok {
        // cluster contains vertex
        does = true
    }
    return
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-27
    • 1970-01-01
    • 1970-01-01
    • 2017-01-14
    • 2017-08-08
    • 1970-01-01
    • 2010-10-04
    相关资源
    最近更新 更多