在Go语言中,int类型的最大值是多少?

234

如何指定无符号整型的最大值?

我想知道如何在下面的循环中初始化min,该循环从一些结构体中迭代地计算最小值和最大长度。

var minLen uint = ???
var maxLen uint = 0
for _, thing := range sliceOfThings {
  if minLen > thing.n { minLen = thing.n }
  if maxLen < thing.n { maxLen = thing.n }
}
if minLen > maxLen {
  // If there are no values, clamp min at 0 so that min <= max.
  minLen = 0
}

这样第一次比较时,minLen >= n


5
请看这段代码片段 int(^uint(0) >> 1) // largest int,它来自于 https://golang.org/doc/effective_go.html#printing。 - Victor
13个回答

326

https://groups.google.com/group/golang-nuts/msg/71c307e4d73024ce?pli=1

以下是相关内容:

由于整数类型使用二进制补码算法,您可以推断出 intuint 的最小/最大常量值。例如,

const MaxUint = ^uint(0) 
const MinUint = 0 
const MaxInt = int(MaxUint >> 1) 
const MinInt = -MaxInt - 1

根据 @CarelZA 的评论:

uint8  : 0 to 255 
uint16 : 0 to 65535 
uint32 : 0 to 4294967295 
uint64 : 0 to 18446744073709551615 
int8   : -128 to 127 
int16  : -32768 to 32767 
int32  : -2147483648 to 2147483647 
int64  : -9223372036854775808 to 9223372036854775807

178
请使用math包中提供的常量:https://golang.org/pkg/math/#pkg-constants,你可能会需要使用`math.MaxInt32`。 - Charles L.
10
请问能否提供更多上下文信息,以便更好地理解这个问题? - Arijoon
27
@Arijoon,符号^表示反转表达式中的位。如果uint(0) == 0000...0000(根据构建目标架构精确地有32位或64位零位),那么^unit(0) == 1111...1111,这给我们提供了无符号整数的最大值(全部为1)。现在,当您谈论带符号整数时,第一个(最高有效)位用于存储符号,因此对于有符号整数的最大值,我们需要将所有位向右移动,这会给我们^uint(0) >> 1 == 0111...1111。这给出了最大的正整数。 - ninjaboy
5
@CharlesL. 仅使用 int 类型怎么样? - Imran Qadir Baksh - Baloch
6
虽然已经过了一段时间,但是以防今天有人来看@user960567的问题评论,请注意:在32位系统上,“int”类型长度为32位,在64位系统上长度为64位。请参见这里 - Christoph Float
显示剩余5条评论

93

4
谢谢。实际上我使用的是uint,而不是uint32lencap使用的是int而不是int32,因此我希望在所有架构上都能匹配它们的大小。math/const.go定义了一堆Max<type>,但没有定义uintint的任何类型。 - Mike Samuel
我会将其更改为uint32或unit64,以确保它在不同架构之间具有可移植性。我对所有事情都这样做。我经历了多年在不同架构之间移植C的痛苦,我可以说,“明确表达”将在以后极大地帮助。 - Deleted
1
谢谢。我的代码有检查uint(len(...)) < thing.minLen,但我不知道uint64(int)是否是并将保持定义行为。 - Mike Samuel
1
如果您不知道,请阅读上面链接的规范...特别是http://golang.org/doc/go_spec.html#Conversions。这里有一个关于“数字类型之间的转换”的仔细定义。 - Anschel Schaffer-Cohen

81

我会使用math包来获取整数的最大值和最小值:

package main

import (
    "fmt"
    "math"
)

func main() {
    // integer max
    fmt.Printf("max int64   = %+v\n", math.MaxInt64)
    fmt.Printf("max int32   = %+v\n", math.MaxInt32)
    fmt.Printf("max int16   = %+v\n", math.MaxInt16)

    // integer min
    fmt.Printf("min int64   = %+v\n", math.MinInt64)
    fmt.Printf("min int32   = %+v\n", math.MinInt32)

    fmt.Printf("max float64 = %+v\n", math.MaxFloat64)
    fmt.Printf("max float32 = %+v\n", math.MaxFloat32)

    // etc you can see more int the `math`package
}

输出:

max int64   = 9223372036854775807
max int32   = 2147483647
max int16   = 32767
min int64   = -9223372036854775808
min int32   = -2147483648
max float64 = 1.7976931348623157e+308
max float32 = 3.4028234663852886e+38

3
这段代码无法运行。两个 int64 溢出了 int 类型,这是因为在字符串插值之前没有显式指定常量类型。请改用 int64(math.MaxInt64),参见 https://dev59.com/A2Qn5IYBdhLWcg3w5qpg - domoarigato
3
但是,否定已接受答案比肯定更好。 :) - domoarigato
如果在一个32位字长的机器上使用int64会发生什么?在C语言中,编译器决定INT_MIN。 - segue_segway

24
< p > 注意:截至Go 1.17,本答案已被取代,其中包括e8eb1d8;即math包现在包括math.MaxUintmath.MaxIntmath.MinInt常量。

简要概述:

import "math/bits"
const (
    MaxUint uint = (1 << bits.UintSize) - 1
    MaxInt int = (1 << bits.UintSize) / 2 - 1
    MinInt int = (1 << bits.UintSize) / -2
)

背景:

我想你已经知道,uint类型与平台上的uint32uint64大小相同。通常情况下,只有在不存在接近最大值的风险时才会使用这些未指定大小的版本,因为未指定大小的版本可以使用“本机”类型,具体取决于平台,这往往更快。

请注意,它倾向于更快是因为有时使用非本机类型需要处理器执行额外的数学运算和边界检查,以模拟更大或更小的整数。考虑到这一点,要意识到处理器(或编译器优化的代码)的性能几乎总是比添加自己的边界检查代码更好,因此,如果存在任何风险可能会产生影响,则使用固定大小的版本并让优化的模拟处理其任何后果可能是有意义的。

话说回来,仍然有一些情况下,了解你正在处理的内容是很有用的。

包“math/bits”包含uint的位数。要确定最大值,请将1左移该位数减1. 即:(1 << bits.UintSize) - 1

请注意,当计算uint的最大值时,通常需要将其明确放入一个uint(或更大)变量中,否则编译器可能会失败,因为它将默认尝试将该计算分配到带符号的int中(显然,它不适合这里),所以:

const MaxUint uint = (1 << bits.UintSize) - 1

这是您问题的直接答案,但您也可能对一些相关计算感兴趣。

根据规范uintint始终具有相同的大小。

uint 32位或64位

intuint相同大小

因此,我们还可以使用该常量来确定int的最大值,方法是将相同的答案除以2然后减去1。 即:(1 << bits.UintSize) / 2 - 1

并且通过将1向左移动那么多位并将结果除以-2,来确定int的最小值。即:(1 << bits.UintSize) / -2

总结一下:

MaxUint: (1 << bits.UintSize) - 1

MaxInt: (1 << bits.UintSize) / 2 - 1

MinInt: (1 << bits.UintSize) / -2

完整示例(应该与上述相同)

package main

import "fmt"
import "math"
import "math/bits"

func main() {
    var mi32 int64 = math.MinInt32
    var mi64 int64 = math.MinInt64
    
    var i32 uint64 = math.MaxInt32
    var ui32 uint64 = math.MaxUint32
    var i64 uint64 = math.MaxInt64
    var ui64 uint64 = math.MaxUint64
    var ui uint64 = (1 << bits.UintSize) - 1
    var i uint64 = (1 << bits.UintSize) / 2 - 1
    var mi int64 = (1 << bits.UintSize) / -2
    
    fmt.Printf(" MinInt32: %d\n", mi32)
    fmt.Printf(" MaxInt32:  %d\n", i32)
    fmt.Printf("MaxUint32:  %d\n", ui32)
    fmt.Printf(" MinInt64: %d\n", mi64)
    fmt.Printf(" MaxInt64:  %d\n", i64)
    fmt.Printf("MaxUint64:  %d\n", ui64)
    fmt.Printf("  MaxUint:  %d\n", ui)
    fmt.Printf("   MinInt: %d\n", mi)
    fmt.Printf("   MaxInt:  %d\n", i)
}

谢谢。您对本地数字的警告表述得非常清楚,而且我之前不知道math/bits。 - Mike Samuel
无符号整数uint为32位或64位,有符号整数int与uint大小相同。如果一个有符号,另一个没有符号,怎么可能是相同的大小呢? - themiDdlest
它们具有相同的位大小,但它们没有相同的最大/最小值。在该大小中,其中一个位是符号位。 (/2 部分是在计算 int64 的最小/最大值大小时从考虑中删除该位的内容) - Will Palmer

14

我最初使用了@nmichaels在他的回答中使用的代码。现在我使用了稍微不同的计算方法。我已经添加了一些注释,以防其他人有与@Arijoon相同的疑问。

const (
    MinUint uint = 0                 // binary: all zeroes

    // Perform a bitwise NOT to change every bit from 0 to 1
    MaxUint      = ^MinUint          // binary: all ones

    // Shift the binary number to the right (i.e. divide by two)
    // to change the high bit to 0
    MaxInt       = int(MaxUint >> 1) // binary: all ones except high bit

    // Perform another bitwise NOT to change the high bit to 1 and
    // all other bits to 0
    MinInt       = ^MaxInt           // binary: all zeroes except high bit
)

最后两个步骤之所以可行,是因为在二进制补码算术中如何表示正数和负数。Go 语言规范的 数值类型 部分将读者指向相关的 Wikipedia 文章。我没有阅读过那篇文章,但我从 Charles Petzold 的书 《编码:隐匿在计算机软硬件背后的语言》 中了解了二进制补码,这是一本非常易于理解的介绍计算机和编程基础的入门书。

我将上面的代码(除大部分注释外)放入了一个小型的 整数数学包 中。


11

Go-1.17现在在math包中定义了MaxUintMaxIntMinInt常量。

package main

import "fmt"
import "math"

const maxUint = uint(math.MaxUint)

func main() {
    fmt.Println("Integer range on your system")

    // .Println("MaxUint:", math.MaxUint)  ERROR constant 18446744073709551615 overflows int
    fmt.Println("MaxUint:", maxUint)

    fmt.Println("MinInt:", math.MinInt)
    fmt.Println("MaxInt:", math.MaxInt)
}

math 包现在定义了三个新的常量:MaxUintMaxIntMinInt
对于 32 位系统,它们的值分别为 2^32 - 12^31 - 1-2^31
对于 64 位系统,它们的值分别为 2^64 - 12^63 - 1-2^63

const (
    MaxInt    = 1<<(intSize-1) - 1   // New
    MinInt    = -1 << (intSize - 1)  // New
    MaxInt8   = 1<<7 - 1
    MinInt8   = -1 << 7
    MaxInt16  = 1<<15 - 1
    MinInt16  = -1 << 15
    MaxInt32  = 1<<31 - 1
    MinInt32  = -1 << 31
    MaxInt64  = 1<<63 - 1
    MinInt64  = -1 << 63
    MaxUint   = 1<<intSize - 1       // New
    MaxUint8  = 1<<8 - 1
    MaxUint16 = 1<<16 - 1
    MaxUint32 = 1<<32 - 1
    MaxUint64 = 1<<64 - 1
)

另请参阅 Go 代码:https://github.com/golang/go/blob/master/src/math/const.go#L39


9

7
使用在math包中定义的常量
const (
    MaxInt8   = 1<<7 - 1
    MinInt8   = -1 << 7
    MaxInt16  = 1<<15 - 1
    MinInt16  = -1 << 15
    MaxInt32  = 1<<31 - 1
    MinInt32  = -1 << 31
    MaxInt64  = 1<<63 - 1
    MinInt64  = -1 << 63
    MaxUint8  = 1<<8 - 1
    MaxUint16 = 1<<16 - 1
    MaxUint32 = 1<<32 - 1
    MaxUint64 = 1<<64 - 1
)

3

解决这个问题的一种方法是从数值本身获取起始点:

var minLen, maxLen uint
if len(sliceOfThings) > 0 {
  minLen = sliceOfThings[0].minLen
  maxLen = sliceOfThings[0].maxLen
  for _, thing := range sliceOfThings[1:] {
    if minLen > thing.minLen { minLen = thing.minLen }
    if maxLen < thing.maxLen { maxLen = thing.maxLen }
  }
}

2
Go 1.17(2021年第4季度)可能会有所帮助,正如Go101所指出的那样,提交 e8eb1d8

Before Go 1.17, we can use the following trick to define MaxInt:

const MaxInt = int(^uint(0) >> 1)

Since Go 1.17, we can directly use math.MaxInt instead

这修复了问题28538,由Silentd00m报告,经CL 247058审核。

由于我们有int8int64min maxuint8uint64max常量,所以我们可能也应该为字长类型定义一些。

测试说明了这是如何工作的:

    if v := int(MaxInt); v+1 != MinInt {
        t.Errorf("MaxInt should wrap around to MinInt: %d", v+1)
    }
    if v := int8(MaxInt8); v+1 != MinInt8 {
        t.Errorf("MaxInt8 should wrap around to MinInt8: %d", v+1)
    }
    if v := int16(MaxInt16); v+1 != MinInt16 {
        t.Errorf("MaxInt16 should wrap around to MinInt16: %d", v+1)
    }
    if v := int32(MaxInt32); v+1 != MinInt32 {
        t.Errorf("MaxInt32 should wrap around to MinInt32: %d", v+1)
    }
    if v := int64(MaxInt64); v+1 != MinInt64 {
        t.Errorf("MaxInt64 should wrap around to MinInt64: %d", v+1)
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接