为什么没有?

我们知道go语言math包里面定义了min/max函数,但是是float64类型的,而并没有整数类型的min/max。

go语言的math包里面定义的min/max函数如下:

1
2
math.Min(float64, float64) float64
math.Max(float64, float64) float64

事实上我们更经常要比较的是两个整数的场景:

1
2
math.Min/Max(int, int), or
math.Min/Max(int64, int64)

那么,为什么go语言不提供整数类型的min/max这两个函数呢? 下面的这篇文章给了一个解释:

https://mrekucci.blogspot.jp/2015/07/dont-abuse-mathmax-mathmin.html

总结起来,主要理由是说,

由于float64类型要处理infinity和not-a-number这种值,而他们的处理非常复杂,一般用户没有能力,所有go需要为用户提供系统级别的解决办法。整数类型不需要实现这样的值。

结论就是说go希望用户自己来实现如此简单的函数。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
func Min(x, y int64) int64 {
    if x < y {
        return x
    }
    return y
}

func Max(x, y int64) int64 {
    if x > y {
        return x
    }
    return y
}

不要滥用math.Max / math.Min

许多人,特别是Go的新人(当然,并非所有人)都倾向于以类似于以下的方式滥用包装中的功能math.Min和 math.Max功能math:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
package main

import (
    "fmt"
    "math"
)

func main() {
    ints := []int{1, 2, 3, 4, 5}
    max := 0

    for _, n := range ints {
        max = int(math.Max(float64(max), float64(n)))
    }

    fmt.Println(max)
}

这个特定的代码示例工作正常,但它包含潜在的错误。这行max = int(math.Max(float64(max), float64(n)))不仅看起来难以辨认,而且错了!

那究竟是什么问题呢?答案很简单:尝试float64用作整数运算的中间体。但是,澄清这个答案并不像预期的那样简单明了。让我们退一步看看Go的浮点类型。Go使用IEEE-754表示浮点数。也就是说,32位float32和64位float64类型被分为三个主要部分(符号,指数和分数位):

请注意,通过使用此表,我们可以轻松计算两个精度的最大值:

MaxFloat32

MaxFloat64

我们还可以轻松计算这些精度的

SmallestNonzeroFloat32

SmallestNonzeroFloat64

此外,您可以在Go包math中找到这些常量。

您可能已经注意到,float类型(float32和float64)的最大值远大于它们对应的整数类型(int32和int64)。

因为这个世界上没有任何东西是免费的,所以IEEE-754浮点表示也有自己的权衡。除了精度有限外,它在表示积分值方面也有局限性。在64位平台上,Go float64类型只能表示和之间的整数值。当int64此范围之外的值转换为float64值时,转换后的值并不总是与输入值匹配。请考虑以下示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package main

import "fmt"

func main() {
    i := int64(1<<53 + 1)
    fmt.Printf("%T: %d\n", i, i)

    f := float64(i64)
    fmt.Printf("%T: %f\n", f, f)
}

// Output:
// int64: 9007199254740993
// float64: 9007199254740992.000000

如您所见,这些值根本不匹配!更糟糕的是,它们可以是相同的:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package main

import "fmt"

func main() {
    x := int64(1 << 60)
    y := x + 127
    fx, fy := float64(x), float64(y)

    fmt.Printf("x: %f; y: %f\n", fx, fy)
    fmt.Printf("x == y => %t\n", fx == fy)

// Output:
// x: 1152921504606846976.000000; y: 1152921504606846976.000000
// x == y => true

当转换到范围之外的值时 int3转换为float32时可能会遇到类似的情况。